시스템 폰트 크기 변경시 UI 이슈 대응하기

대부분의 안드로이드 사용자의 경우에는 폰트의 크기를 default 사이즈로 사용해서 특별히 문제가 없지만, 나이가 드신 분들이나 작은 글자의 인식이 불편해서 글자의 크기를 크게(최대로) 해서 보시는 분들도 있다. 이 경우에는 앱에서 이 경우를 대비해서 대응하지 않으면 글자의 위/아래가 잘리는 경우를 볼 수 있다.

우선 폰트의 크기를 설정 앱에서 변경해 보자. 갤럭시를 기준으로 살펴보면 Settings > Display > Font size and style 에서 아래와 같이 폰트의 크기를 변경할 수 있다.

다음으로, 위 화면과 같이 폰트의 크기를 최대로 변경한 경우, 앱에서 어떻게 보이는지 살펴보자. 예로 아래의 화면과 아래의 코드가 이 경우에 해당한다.

그리고, 위 화면을 보여주는 텍스트 뷰의 간략한 코드는 아래와 같다.

<TextView
android:id="@+id/fg_docs_item_detail"
android:layout_width="0dp"
android:layout_height="28dp"
..... />

다음으로, 이 문제를 해결하기 위한 방안을 살펴보자. 간단하게 UI(XML) 코드를 아래와 같이 개선하면 된다. android:layout_height은 글자 크기에 따라서 커질 수 있게 처리(wrap_content)하고, android:minHeight은 기존의 컴포넌트 크기로 고정한다. 그리고, 아래 UI를 포함하는 뷰 그룹(Linear, Relative, Fragme, Constraint)들도 아래와 같이 처리하면 안드로이드 시스템 폰트의 크기를 변경해도 앱 화면의 UI가 잘리지 않게 된다.

<TextView
android:id="@+id/fg_docs_item_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:minHeight="28dp"
..... />

마지막으로, 위 코드를 적용한 앱의 화면을 아래에서 볼 수 있다. 이 화면에서는 글자가 커지긴 했지만, 잘리지 않고 잘 보이는 것을 알 수 있다.

안드로이드 앱 폰트 전체를 변경해 보자..

안드로이드 앱을 개발하다 보면 종종 폰트가 맘에 안 드는 경우가 발생한다. 안드로이드 4.1.x 이후부터는 새로운 폰트가 추가되서 조금 만족스러운 결과를 보여준다. 하지만 그것도 맘에 안 드는 경우나 앱 전체에 같은 폰트를 사용해서 일관성 있는 UI를 표현하고 싶은 경우도 있다. 안드로이드 개별 컴포넌트의 폰트를 변경하는 것은 어렵지 않다. 여기서는 앱 전체 폰트를 한 번에 변경하는 방법에 대해 살펴보겠다. 아래 내용은 안드로이드 2.3 이상의 버전에서 앱 전체 폰트를 변경하는 예제이다.

1. 원하는 폰트(Roboto-Light.ttf)를 assets 폴더에 카피한다.

2. Application 클래스를 상속해서 아래(FontApplication)와 같이 구현한다.

package net.sjava.example.font_reflector; 
import java.lang.reflect.Field;
import android.app.Application;
import android.content.Context;
import android.graphics.Typeface;

public class FontApplication extends Application {
	@Override
	public void onCreate() {
		setDefaultFont(this, "DEFAULT", "Roboto-Light.ttf");
		setDefaultFont(this, "SANS_SERIF", "Roboto-Light.ttf");
		setDefaultFont(this, "SERIF", "Roboto-Light.ttf");
	}

	public static void setDefaultFont(Context ctx,
			String staticTypefaceFieldName, String fontAssetName) {
		final Typeface regular = Typeface.createFromAsset(ctx.getAssets(),
				fontAssetName);
		replaceFont(staticTypefaceFieldName, regular);
	}

	protected static void replaceFont(String staticTypefaceFieldName,
			final Typeface newTypeface) {
		try {
			final Field StaticField = Typeface.class
					.getDeclaredField(staticTypefaceFieldName);
			StaticField.setAccessible(true);
			StaticField.set(null, newTypeface);
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}
}

이 과정은 Application 클래스(앱의 시작과 종료 사이클을 가지고 있는 클래스)를 사용한다. 앱이 시작할 때 리플렉션을 이용해서 폰트를 재설정하는 방식(http://stackoverflow.com/questions/2711858/is-it-possible-to-set-font-for-entire-application?rq=1) 이다.

3. AndroidManifest.xml파일에 위의 클래스 이름(FontApplication)을 등록한다.

4. values/styles.xml 파일을 아래의 형태로 수정한다.

<resources>
    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
        <item name="android:typeface">sans</item>
    </style>

    <style name="AppTheme.DialogWhenLarge" parent="@android:style/Theme.Holo.Light.DialogWhenLarge">
        <item name="android:typeface">sans</item>
    </style>
</resources>

위 과정으로, 앱에서 표현되는 모든 문자는 FontApplication 클래스에서 등록한 폰트로 바뀌는 것을 볼 수 있다. 아래는 안드로이드 에뮬레이터 2.3버전에서 확인한 화면이다.
 

5. 추가 테마에서도 글꼴을 바꿔보자.
위의 4.에서 본 styles.xml 예제는 안드로이드 2.3의 예제이고 정말 간단한 예이다. 아마도 하나의 Theme만을 쓰는 쓰는 앱은 거의 없을 테니, 다른 테마에서 적용하는 방법을 살펴보자. 아래의 예제는 values-v11/styles.xml을 약간 수정한 파일이다. 위에서 안드로이드의 Theme.Holo.Light.DialogWhenLarge 테마를 AppTheme.DialogWhenLarge가 상속을 받고, 폰트만 재 정의 했다. 아래에서는 위에서 정의한 AppTheme.DialogWhenLarge를 적용한 AndroidManifest.xml의 Application 영역 부분이다.

<application 
    android:allowBackup="true" 
    android:icon="@drawable/ic_launcher"             
    android:label="@string/app_name"                    
    android:name=".FontApplication"             
    android:theme="@style/AppTheme" >
    <activity 
        android:name="net.sjava.example.font_reflector.IndexActivity"
        android:theme="@style/AppTheme.DialogWhenLarge"                 
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

위에서 살펴본 앱 폰트를 한 번에 변경하는 예제는 아래에서 다운받을 수 있다.
cfile30.uf.2302334A51CA70FD162EF6.zip

Ubuntu에서 Adobe가 배포하는 SourceCodePro, SourceSansPro 폰트 사용하기..

Adobe에서 배포한 SourceCodePro, SourceSansPro 폰트를 우분투에서 사용하는 방법입니다. 최근에 Tweet으로 SourceCodePro가 좋다고 하신 분이 계셔서, Adobe가 Github에서 공개하는 폰트를 찾아보니 SourceSansPro 폰트가 더 있어서, 두 개다 설치하는 방법이다.

아래의 URL에서 2개의 폰트를 다운로드 받는다.
https://github.com/adobe-fonts/source-code-pro
https://github.com/adobe-fonts/source-sans-pro

위 2개의 폰트중에 SourceCodePro 파일을 풀면 아래와 같은 구조를 볼 수 있고, OTF, TTF 둘 다 가지고 있다. OTF와 TTF는 OpenType의 글꼴로, 자세한 내용은 http://en.wikipedia.org/wiki/OpenType에서 볼 수 있다.

drwxr-xr-x  4 mcsong mcsong  4096 Jun 19 10:16 ./
drwxr-xr-x 41 mcsong mcsong 20480 Jun 19 10:16 ../
-rwxr-xr-x  1 mcsong mcsong  4622 Jan 16 13:48 LICENSE.txt*
drwxr-xr-x  2 mcsong mcsong  4096 Jun 19 10:16 OTF/
-rwxr-xr-x  1 mcsong mcsong  4402 Jan 16 13:48 ReadMe.html*
-rwxr-xr-x  1 mcsong mcsong 12328 Jan 16 13:48 SourceCodeProReadMe.html*
drwxr-xr-x  2 mcsong mcsong  4096 Jun 19 10:16 TTF/

각 폰트가 제공하는 2가지 타입중에서, TTF 폰트를 사용하는 방법을 살펴본다. SourceCodePro를 사용하는 예를 살펴보면..

sudo mkdir /usr/share/fonts/truetype/sourcecodepro <– SourceSansPro는 sourcesanspro 폴더를 만든다.
sudo cp *.ttf /usr/share/fonts/truetype/sourcecodepro/ <– 위의 TTF 폴더에서 복사
sudo fc-cache -f -v <– 폰트 캐시 다시 로딩

위의 과정을 SourceSansPro에 대해서도 동일하게 적용한다. 그리고, 폰트 캐시를 리프레시하면 아래의 결과를 볼 수 있다.

/usr/share/fonts/truetype/sourcecodepro: caching, new cache contents: 7 fonts, 0 dirs
/usr/share/fonts/truetype/sourcesanspro: caching, new cache contents: 12 fonts, 0 dirs

위의 과정으로 Adobe에서 배포하는 SourceCodePro와 SourceSansPro 폰트를 사용할 수 있겠다. 개인적으로는 SourceSansPro보다는 SourceCodePro가 코딩할 때 가독성이 좋게 느껴진다.. ^^