안드로이드 텍스트뷰 속성 8. [fontFamily, fontFeatureSettings] (Android TextView Attributes 8)

2016. 10. 6. 10:49


1. TextView 속성 (8)

TextView 속성 리스트 및 요약 설명을 확인하시려면 [안드로이드 텍스트뷰 속성] 페이지를 참고하시기 바랍니다.


TextView 속성에 대한 자세한 설명 및 예제를 확인하시려면, 아래 표에서 속성 이름을 클릭하시기 바랍니다.


속성 속성 속성 속성 속성
autoLink autoText breakStrategy bufferType capitalize
cursorVisible digits drawableBottom drawableEnd drawableLeft
drawablePadding drawableRight drawableStart drawableTint drawableTintMode
drawableTop editable editorExtras elegantTextHeight ellipsize
ems fontFamily fontFeatureSettings freezesText gravity
height hint hyphenationFrequency imeActionId imeActionLabel
imeOptions includeFontPadding inputMethod inputType letterSpacing
lineSpacingExtra lineSpacingMultiplier lines linksClickable marqueeRepeatLimit
maxEms maxHeight maxLength maxLines maxWidth
minEms minHeight minLines minWidth numeric
password phoneNumber privateImeOptions scrollHorizontally selectAllOnFocus
shadowColor shadowDx shadowDy shadowRadius singleLine
text textAllCaps textAppearance textColor textColorHighlight
textColorHint textColorLink textIsSelectable textScaleX textSize
textStyle typeface width

2. TextView 속성 활용

2.1 TextView 폰트 설정 (fontFamily)

TextView에 출력되는 텍스트의 폰트를 설정하려면 "fontFamily" 속성을 사용합니다.

  * android:fontFamily - TextView의 텍스트 폰트 설정.
        > 폰트를 지칭하는 문자열 지정. (예. "sans-serif")
        > Android 4.1 (API Level 16)부터 사용 가능.
        > 기본적으로 사용 가능한 값 . (Android 6.0 (API Level 23) 기준.)
          -. sans-serif
          -. sans-serif-thin
          -. sans-serif-light
          -. sans-serif-medium
          -. sans-serif-black
          -. sans-serif-condensed
          -. arial                  (alias to sans-serif)
          -. helvetica              (alias to sans-serif)
          -. tahoma                 (alias to sans-serif)
          -. verdana                (alias to sans-serif)
          -. serif 
          -. times                  (alias to serif)
          -. times new roman        (alias to serif)
          -. monospace
        > sans-serif(Roboto), serif(Noto), monospace(Droid Sans)

fontFamily 속성을 사용하여 TextView의 폰트를 변경하는 것은 간단합니다. fontFamily 속성에 폰트를 지칭하는 문자열인 "폰트 이름"을 지정하기만 하면 되죠. 그런데, 사용법은 정말 간단하지만... 한 가지 문제가 있습니다. 폰트를 지칭하는 "폰트 이름"에 어떤 값을 적어야 할지 모른다는 것입니다. 즉, fontFamily 속성 값에 사용할 수 있는 "폰트 이름"에는 어떤 종류가 있으며, 화면에 어떻게 표시되는지 모른다는 것이죠. 아니, 더 나아가 안드로이드에서 사용할 수 있는 폰트의 종류에는 어떤 것들이 있는지부터 궁금하군요.


먼저, 안드로이드에서 제공하는 폰트의 종류부터 차근차근 살펴보도록 하겠습니다.

2.1.1 Roboto와 Noto

안드로이드 디자인 가이드라인의 Typography(활자, [Android Style - Typography]) 문서에 나와 있듯이, 안드로이드의 기본 폰트는 "Roboto"입니다. "Roboto"폰트는 구글에서 개발한 폰트이며, 안드로이드에서 사용하기 위해 만들어졌습니다. 하지만 "Roboto"는 영문 폰트(English, English-like)만 지원하기 때문에, 한글 폰트를 출력할 때는 "Noto" 폰트가 사용됩니다. "Noto" 폰트(http://www.google.com/get/noto/) 또한 구글에서 만든 폰트이며, "Beautiful and free fonts for all languages"라는 제목답게 모든 언어를 지원하는 무료 폰트입니다.


"Roboto" 폰트는 Android 4.1(API Level 16)부터 추가되어 안드로이드의 기본 폰트로 사용되고 있습니다.


[Android 4.1 APIs - Font families]에 나와있듯이, regular(보통), light(선이 얇은), condensed(폭이 좁은) 스타일의 "Roboto" 폰트를 사용할 수 있으며, 각각 fontFamily 속성에 "sans-serif", "sans-serif-light", "sans-serif-condensed"라는 값으로 사용됩니다. 또한 "textStyle" 속성(bold, italic)과 조합되어 최종적으로 표시될 폰트 파일이 선택됩니다. (Android 5.0에서는 "sans-serif-mediaum"과 "sans-serif-black"이 새로 추가되었습니다.)


아래는 fontFamily 속성에 사용할 수 있는, "sans-serif", "sans-serif-light", "sans-serif-condensed" 값과 textStyle 속성 값 조합으로 표시될 수 있는 최종 폰트 출력 모양을 확인할 수 있는 예제입니다.

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:fontFamily="sans-serif"
            android:text="ABCabc123가나다 - sans-serif, regular" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:fontFamily="sans-serif"
            android:textStyle="italic"
            android:text="ABCabc123가나다 - sans-serif, italic" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:fontFamily="sans-serif"
            android:textStyle="bold"
            android:text="ABCabc123가나다 - sans-serif, bold" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:fontFamily="sans-serif"
            android:textStyle="italic|bold"
            android:text="ABCabc123가나다 - sans-serif, bold-italic" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:fontFamily="sans-serif-light"
            android:text="ABCabc123가나다 - sans-serif, regular" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:fontFamily="sans-serif-light"
            android:textStyle="italic"
            android:text="ABCabc123가나다 - sans-serif, italic" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:fontFamily="sans-serif-condensed"
            android:text="ABCabc123가나다 - sans-serif-condensed, regular" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:fontFamily="sans-serif-condensed"
            android:textStyle="italic"
            android:text="ABCabc123가나다 - sans-serif-condensed, italic" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:fontFamily="sans-serif-condensed"
            android:textStyle="bold"
            android:text="ABCabc123가나다 - sans-serif-condensed, bold" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:fontFamily="sans-serif-condensed"
            android:textStyle="italic|bold"
            android:text="ABCabc123가나다 - sans-serif-condensed, bold-italic" />

    </LinearLayout>

fontFamily 속성 기본 예제


그런데 안드로이드에서는 "Roboto" 폰트만 사용할 수 있을까요? 분명 안드로이드 기기들을 보면 "Roboto" 외에 다양한 폰트들이 사용되고 있는 것을 확인할 수 있는데 말이죠. 그리고 그런 폰트들의 "폰트 이름"은 또 어디서 확인할 수 있을까요?


질문에 대한 답을 하자면, 당연히 "Roboto" 폰트 뿐만 아니라 안드로이드 기기 제조사에서 자체적으로 탑재한 다양한 폰트들을 사용할 수 있습니다. 또한 안드로이드 시스템 내부에서 관리하는 폰트 정보 파일에서 "폰트 이름"을 확인할 수 있습니다.


안드로이드에서 제공하는 폰트 파일(.ttf)들은 안드로이드 기기의 "/system/fonts/" 디렉토리에 저장되어 있습니다. 하지만 파일 이름이 직접 "폰트 이름"으로 사용되는 것은 아닙니다. 대신, 각 폰트 파일(.ttf)을 앱에서 불러다 쓸 수 있는 "폰트 이름" 정보를 별도의 xml 파일에 저장하고 있습니다. "/system/etc/fonts.xml" 파일이 바로 그것입니다.

2.1.2 "/system/etc/fonts.xml" (Android 5.0, API Level 21 이상)

"/system/etc/fonts.xml" 파일은 안드로이드 시스템 폰트 설정 정보가 저장된 파일입니다. Android 5.0 (API Level 21) 이상의 안드로이드 프레임워크는 이 파일에서 시스템 폰트 정보를 읽어들입니다.


"/system/etc/fonts.xml" 파일을 열어보면 아래와 같은 내용이 저장되어 있습니다. ("/system/etc/fonts.xml" 파일의 내용은 안드로이드 기기의 제조사 및 버전에 따라 다른 내용을 포함할 수 있습니다.)

<familyset version="22">
    <!-- first font is default -->
    <family name="sans-serif">
        <font weight="100" style="normal">Roboto-Thin.ttf</font>
        <font weight="100" style="italic">Roboto-ThinItalic.ttf</font>
        <font weight="300" style="normal">Roboto-Light.ttf</font>
        <font weight="300" style="italic">Roboto-LightItalic.ttf</font>
        <font weight="400" style="normal">Roboto-Regular.ttf</font>
        <font weight="400" style="italic">Roboto-Italic.ttf</font>
        <font weight="500" style="normal">Roboto-Medium.ttf</font>
        <font weight="500" style="italic">Roboto-MediumItalic.ttf</font>
        <font weight="900" style="normal">Roboto-Black.ttf</font>
        <font weight="900" style="italic">Roboto-BlackItalic.ttf</font>
        <font weight="700" style="normal">Roboto-Bold.ttf</font>
        <font weight="700" style="italic">Roboto-BoldItalic.ttf</font>
    </family>

    <!-- Note that aliases must come after the fonts they reference. -->
    <alias name="sans-serif-thin" to="sans-serif" weight="100" />
    <alias name="sans-serif-light" to="sans-serif" weight="300" />
    <alias name="sans-serif-medium" to="sans-serif" weight="500" />
    <alias name="sans-serif-black" to="sans-serif" weight="900" />
    <alias name="arial" to="sans-serif" />
    <alias name="helvetica" to="sans-serif" />
    <alias name="tahoma" to="sans-serif" />
    <alias name="verdana" to="sans-serif" />

    <!-- ... -->

    <family name="serif">
        <font weight="400" style="normal">NotoSerif-Regular.ttf</font>
        <font weight="700" style="normal">NotoSerif-Bold.ttf</font>
        <font weight="400" style="italic">NotoSerif-Italic.ttf</font>
        <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font>
    </family>

    <!-- ... -->

    <family name="monospace">
        <font weight="400" style="normal">DroidSansMono.ttf</font>
    </family>

    <!-- 내용 계속 -->

</familyset>

선뜻 이해되지 않는, 조금은 복잡한 내용들로 채워져 있는 것을 확인할 수 있는데, 여기서 몇 가지 도움되는 내용들만 짚어보도록 하겠습니다.


먼저, 가장 중요한, fontFamily 속성에 사용할 "폰트 이름"은 "family" 또는 "alias" 태그의 "name" 속성에 설정된 문자열입니다. "폰트 이름"을 위에서부터 나열해보자면, "sans-serif", "sans-serif-thin", "sans-serif-light", "sans-serif-medium", "sans-serif-black", "arial", "helvetica", ... 등등이 되겠죠.


그 다음, "폰트 이름"에 따른 실제 폰트 파일(.ttf) 매칭은 "font" 태그를 사용하여 기술합니다. "font" 태그에는 몇 가지 속성이 사용되는데, "weight" 속성은 글자 획의 굵기(100~900)를 나타내고, "style" 속성은 "normal" 또는 "italic" 속성을 가집니다. 여기서의 "style" 속성은 TextView의 "textStyle" 속성으로부터 전달되는 값입니다. 하지만 TextView의 "textStyle" 속성에서 정의되는 "bold"가 "style" 속성에는 사용되지 않습니다. 대신 "bold"는 "weight" 속성 값에 반영되기 때문이죠. TextView의 "textStyle" 속성에 "bold"가 적용되면 "weight" 값에 300이 더해집니다.


참고로 "bold"가 적용되지 않은 TextView의 텍스트, 즉 "Regular"의, "weight" 값은 400입니다.


마지막으로 "alias" 태그는 앞서 정의된 "family" 태그를 "to" 속성을 통해 참조하며, "weight" 값이 파라미터로 사용될 수 있습니다.

fonts.xml 파일 구성


이제 몇 가지 예제를 통해 TextView의 속성 값(fontFamily, textStyle)이 어떤 폰트를 사용하여 출력되는지 알아보도록 하겠습니다.

[예제-1] fontFamily="sans-serif", textStyle="normal". (= Roboto-Regular.ttf)
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:fontFamily="sans-serif"
        android:text="ABCabc123가나다 - sans-serif, regular" />

fontFamily fonts.xml 예제 1

family가 "sans-serif", 기본 weight 값 400, style은 "normal" 이므로 "Roboto-Regular.ttf" 폰트 파일이 사용됩니다.


[예제-2] fontFamily="sans-serif", textStyle="bold". (= Roboto-Bold.ttf)
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:fontFamily="sans-serif"
        android:textStyle="bold"
        android:text="ABCabc123가나다 - sans-serif, bold" />

fontFamily fonts.xml 예제 2

family는 "sans-serif", textStyle이 bold이므로 weight값은 700(400+300), style은 "bold"이기 때문에 "Roboto-Bold.ttf" 폰트 파일이 사용됩니다.


[예제-3] fontFamily="sans-serif-thin", textStyle="italic". (= Roboto-ThinItalic.ttf)
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:fontFamily="sans-serif-thin"
        android:textStyle="italic"
        android:text="ABCabc123가나다 - sans-serif-thin, italic" />

fontFamily fonts.xml 예제 3

"sans-serif-thin"라는 alias가 "sans-serif"를 가리키고, weight 파라미터는 100, style이 "italic"이므로, "Roboto-ThinItalic.ttf" 폰트 파일이 사용됩니다.


[예제-4] fontFamily="arial", textStyle="italic". (= Roboto-Italic.ttf)
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:fontFamily="arial"
        android:textStyle="italic"
        android:text="ABCabc123가나다 - arial, italic" />

fontFamily fonts.xml 예제 4

"arial"은 "sans-serif"를 가리키고, weight는 기본 400, style이 "italic"이므로, "Roboto-Italic.ttf" 폰트 파일이 사용됩니다.


[예제-5] fontFamily="serif", textStyle="normal". (= NotoSerif-Regular.ttf)
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:fontFamily="serif"
        android:text="ABCabc123가나다 - serif, normal" />

fontFamily fonts.xml 예제 5

family는 "serif", textStyle이 regular이므로 weight값은 400, style은 "normal"이기 때문에 "NotoSerif-Regular.ttf" 폰트 파일이 사용됩니다.

2.1.3 "/system/etc/system_fonts.xml" (Android 5.0, API Level 21 이전)

"/system/etc/system_fonts.xml"은 Android 5.0 (API Level 21) 이전에 사용하던 폰트 설정 파일입니다. 그렇다고 Android 5.0 이상에서 전혀 사용되지 않는 것은 아닙니다. 앱에 따라 "system_fonts.xml" 파일을 참조하는 경우도 있기 때문에, 안드로이드 시스템을 빌드할 때 "fonts.xml" 파일의 내용에 맞춰 "system_fonts.xml" 파일도 수정 및 유지하도록 권고하고 있습니다.


"/system/etc/system_fonts.xml" 파일의 내용은 다음과 같습니다.

<familyset>

    <family>
        <nameset>
            <name>sans-serif</name>
            <name>arial</name>
            <name>helvetica</name>
            <name>tahoma</name>
            <name>verdana</name>
        </nameset>
        <fileset>
            <file>Roboto-Regular.ttf</file>
            <file>Roboto-Bold.ttf</file>
            <file>Roboto-Italic.ttf</file>
            <file>Roboto-BoldItalic.ttf</file>
        </fileset>
    </family>

    <!-- 내용 계속 -->

</familyset>

"폰트 이름"은 "<family>" 태그의 "<nameset>" 아래에 "<name>"태그에 지정합니다. 위의 내용에서 "sans-serif", "arial", "helvetica", ... 등이 여기에 해당합니다.


폰트 파일은 "<fileset>" 태그 아래의 "<file>" 태그에 기술합니다. 특히 "<file>" 태그는 4개가 사용되며, 순서대로 regular, bold, italic, bold-italic 스타일에 따른 폰트 파일을 의미합니다.


몇 가지 예제를 통해 폰트 선택 과정을 살펴보겠습니다.

[예제-1] fontFamily="sans-serif", textStyle="normal". (= Roboto-Regular.ttf)
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:fontFamily="sans-serif"
        android:text="ABCabc123가나다 - sans-serif, regular" />

fontFamily system_fonts.xml 예제 1

family가 "sans-serif", regular로 출력되므로 "Roboto-Regular.ttf" 파일이 사용됩니다.


[예제-2] fontFamily="sans-serif", textStyle="bold". (= Roboto-Bold.ttf)
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:fontFamily="sans-serif"
        android:textStyle="bold"
        android:text="ABCabc123가나다 - sans-serif, bold" />

fontFamily system_fonts.xml 예제 2

family는 "sans-serif", textStyle이 bold이므로 "Roboto-Bold.ttf" 파일이 사용됩니다.


[예제-3] fontFamily="helvetica", textStyle="italic|bold". (= Roboto-BoldItalic.ttf)
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:fontFamily="helvetica"
        android:textStyle="italic|bold"
        android:text="ABCabc123가나다 - helvetica, bold+italic" />

fontFamily system_fonts.xml 예제 3

family가 "helvetica", textStyle이 italic+bold이므로 "Roboto-BoldItalic.ttf" 파일이 사용됩니다.


참고로 "/system/etc/system_fonts.xml" 파일에서 매치되지 않는 폰트는 "/system/etc/fallback_fonts.xml" 파일에서 동일한 방법으로 검색됩니다.

2.2 font feature settings (fontFeatureSettings)

"fontFeatureSettings" 속성은 Open Type 폰트(.otf)의 "출력 관련 고급 설정"(advanced typographic features)을 제어할 수 있게 해 줍니다.

  * android:fontFeatureSettings - font feature settings 지정.
        > CSS font-feature-settings에서 사용하는 값과 동일한 형식의 문자열 값 지정.
        > http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings.

fontFeatureSettings 속성에 대한 사용 예제 및 결과 확인은 아래의 링크 주소에서 확인하시기 바랍니다.

[Nutso2 폰트에서 fontFeatureSettings속성을 사용하여 분수(fraction) 표시하기]

3. 참고.


ANDROID 프로그래밍/TEXTVIEW