XML을 사용하여 Android TextView에서 사용자 정의 글꼴 사용


92

내 asset / fonts 폴더에 사용자 정의 글꼴 파일을 추가했습니다. 내 XML에서 어떻게 사용합니까?

다음과 같이 코드에서 사용할 수 있습니다.

TextView text = (TextView) findViewById(R.id.textview03);
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Molot.otf");
text.setTypeface(tf);

android:typeface="/fonts/Molot.otf"속성을 사용하여 XML에서 할 수 없습니까 ?


나는 이것을 많이 검색했으며 xml에서 할 수있는 방법이 없습니다.
— Cd

2
이 게시물을 확인해보십시오. stackoverflow.com/questions/2376250/…
— dor506

한 번 봐 가지고 이 답변을 ! 여러 글꼴과 XML을 사용할 수 있습니다.
— Rafa0809

다른 사람들이 말했듯 이 Calligraphy 를 사용 하여이를 달성 할 수 있습니다 .
— mbonnin

이 기사를 확인하십시오 gadgetsaint.com/tips/…
— ASP

답변:


45

짧은 대답 : 아니요. Android에는 XML을 통해 텍스트 위젯에 사용자 지정 글꼴을 적용하는 기능이 내장되어 있지 않습니다.

그러나 구현하기가 그리 어렵지 않은 해결 방법이 있습니다.

먼저

자신 만의 스타일을 정의해야합니다. / res / values ​​폴더에서 attrs.xml 파일을 열고 / 만들고 다음과 같이 선언 스타일 개체를 추가합니다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="FontText">
        <attr name="typefaceAsset" format="string"/>
    </declare-styleable>
</resources>

둘째

이 위젯을 자주 사용한다고 가정하면로드 된 Typeface객체에 대해 간단한 캐시를 설정해야 합니다. 메모리에서 즉시로드하는 데 시간이 걸릴 수 있기 때문입니다. 다음과 같은 것 :

public class FontManager {
    private static FontManager instance;

    private AssetManager mgr;

    private Map<String, Typeface> fonts;

    private FontManager(AssetManager _mgr) {
        mgr = _mgr;
        fonts = new HashMap<String, Typeface>();
    }

    public static void init(AssetManager mgr) {
        instance = new FontManager(mgr);
    }

    public static FontManager getInstance() {
        if (instance == null) {
            // App.getContext() is just one way to get a Context here
            // getContext() is just a method in an Application subclass
            // that returns the application context
            AssetManager assetManager = App.getContext().getAssets();
            init(assetManager);
        }
        return instance;
    }

    public Typeface getFont(String asset) {
        if (fonts.containsKey(asset))
            return fonts.get(asset);

        Typeface font = null;

        try {
            font = Typeface.createFromAsset(mgr, asset);
            fonts.put(asset, font);
        } catch (Exception e) {

        }

        if (font == null) {
            try {
                String fixedAsset = fixAssetFilename(asset);
                font = Typeface.createFromAsset(mgr, fixedAsset);
                fonts.put(asset, font);
                fonts.put(fixedAsset, font);
            } catch (Exception e) {

            }
        }

        return font;
    }

    private String fixAssetFilename(String asset) {
        // Empty font filename?
        // Just return it. We can't help.
        if (TextUtils.isEmpty(asset))
            return asset;

        // Make sure that the font ends in '.ttf' or '.ttc'
        if ((!asset.endsWith(".ttf")) && (!asset.endsWith(".ttc")))
            asset = String.format("%s.ttf", asset);

        return asset;
    }
}

이 파일은 .ttc 파일 확장자를 사용할 수있게 해주지 만 테스트되지 않았습니다.

제삼

하위 클래스를 만드는 새 클래스를 만듭니다 TextView. 이 특정 예제는 정의 된 XML 서체 ( bold, italic등)를 고려하여 글꼴에 적용합니다 (.ttc 파일을 사용한다고 가정).

/**
 * TextView subclass which allows the user to define a truetype font file to use as the view's typeface.
 */
public class FontText extends TextView {
    public FontText(Context context) {
        this(context, null);
    }

    public FontText(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FontText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        if (isInEditMode())
            return;

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.FontText);

        if (ta != null) {
            String fontAsset = ta.getString(R.styleable.FontText_typefaceAsset);

            if (!TextUtils.isEmpty(fontAsset)) {
                Typeface tf = FontManager.getInstance().getFont(fontAsset);
                int style = Typeface.NORMAL;
                float size = getTextSize();

                if (getTypeface() != null)
                    style = getTypeface().getStyle();

                if (tf != null)
                    setTypeface(tf, style);
                else
                    Log.d("FontText", String.format("Could not create a font from asset: %s", fontAsset));
            }
        }
    }
}

드디어

TextViewXML 의 인스턴스를 정규화 된 클래스 이름으로 바꿉니다 . Android 네임 스페이스처럼 커스텀 네임 스페이스를 선언합니다. "typefaceAsset"은 / assets 디렉토리에 포함 된 .ttf 또는 .ttc 파일을 가리켜 야합니다.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.FontText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is a custom font text"
        custom:typefaceAsset="fonts/AvenirNext-Regular.ttf"/>
</RelativeLayout>

좋은 대답입니다! 하지만 한 가지 질문 : isInEditMode 때 왜 돌아 왔나요?
— Avi Shukron 2015

04-11 18 : 18 : 32.685 3506-3506 / com.example.demo E / AndroidRuntime ﹕ 치명적 예외 : 기본 프로세스 : com.example.demo, PID : 3506 android.view.InflateException : 바이너리 XML 파일 줄 # 2 : 오류 android.view.LayoutInflater.createView (LayoutInflater.java:620)의 com.example.demo.libraries.LatoTextView 클래스를 android.view.LayoutInflater.createViewFromTag (LayoutInflater.java:696)에서 android.view.LayoutInflater.inflate ( LayoutInflater.java:469) at android.view.LayoutInflater.inflate (LayoutInflater.java:397) at ...
— e-info128

@AvrahamShukron는 - (미리보기 모드에서 사용자 지정 서체를 적용 처리하는 방법을 알고하지 않습니다 아마도 때문에 동안 안드로이드 스튜디오에서 오류가 계속 때문이있다.
— themarshal

RelativeLayout에 xmlns : custom = " schemas.android.com/tools "를 추가 했으며 오류가 사라졌습니다. 감사합니다 남자
— Naveed 아마드

1
안녕하세요 @themarshal : 스타일 지정 속성을 사용하려면 xmlns : custom = " schemas.android.com/tools " 대신 xmlns : custom = " schemas.android.com/apk/res-auto "를 사용해야 합니다.
— Abhinav Saxena

28

다음은이를 수행하는 예제 코드입니다. 정적 최종 변수에 글꼴이 정의되어 있고 글꼴 파일은 assets 디렉토리에 있습니다.

public class TextViewWithFont extends TextView {

    public TextViewWithFont(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setTypeface(MainActivity.typeface);
    }

    public TextViewWithFont(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setTypeface(MainActivity.typeface);
    }

    public TextViewWithFont(Context context) {
        super(context);
        this.setTypeface(MainActivity.typeface);
    }

}

5
OP는 특히 그가 프로그래밍 방식으로 글꼴을 설정하는 방법을 알고 있다고 명시합니다 (그는 예를 제공하기도합니다). 문제는 xml에서 글꼴을 설정하는 방법입니다.
— SMBiggs

13

사용하려는 글꼴에 속하는 사용자 지정 TextView를 만듭니다. 이 클래스에서는 정적 mTypeface 필드를 사용하여 Typeface를 캐시합니다 (성능 향상을 위해)

public class HeliVnTextView extends TextView {

/*
 * Caches typefaces based on their file path and name, so that they don't have to be created every time when they are referenced.
 */
private static Typeface mTypeface;

public HeliVnTextView(final Context context) {
    this(context, null);
}

public HeliVnTextView(final Context context, final AttributeSet attrs) {
    this(context, attrs, 0);
}

public HeliVnTextView(final Context context, final AttributeSet attrs, final int defStyle) {
    super(context, attrs, defStyle);

     if (mTypeface == null) {
         mTypeface = Typeface.createFromAsset(context.getAssets(), "HelveticaiDesignVnLt.ttf");
     }
     setTypeface(mTypeface);
}

}

xml 파일에서 :

<java.example.HeliVnTextView
        android:id="@+id/textView1"
        android:layout_width="0dp"
        ... />

자바 클래스에서 :

HeliVnTextView title = new HeliVnTextView(getActivity());
title.setText(issue.getName());

11

액티비티는 생성 된 각 뷰에 콜백을 제공하는 LayoutInflater.Factory2를 구현합니다. 사용자 정의 글꼴 패밀리 속성으로 TextView의 스타일을 지정하고, 요청시 서체를로드하고, 인스턴스화 된 텍스트보기에서 setTypeface를 자동으로 호출 할 수 있습니다.

안타깝게도 활동 및 Windows와 관련된 Inflater 인스턴스의 아키텍처 관계로 인해 Android에서 사용자 지정 글꼴을 사용하는 가장 간단한 방법은로드 된 글꼴을 애플리케이션 수준에서 캐시하는 것입니다.

샘플 코드베이스는 다음과 같습니다.

https://github.com/leok7v/android-textview-custom-fonts

  <style name="Baroque" parent="@android:style/TextAppearance.Medium">
    <item name="android:layout_width">fill_parent</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:textColor">#F2BAD0</item>
    <item name="android:textSize">14pt</item>
    <item name="fontFamily">baroque_script</item>
  </style>

  <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:custom="http://schemas.android.com/apk/res/custom.fonts"
          android:orientation="vertical"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
  >
  <TextView
    style="@style/Baroque"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/sample_text"
  />

결과

여기에 이미지 설명 입력


2 년 동안 그 코드를 건드리지 않았습니다. 하지만 그래야합니다. 나는 이론적으로 그것을 막는 어떤 것도 보지 못합니다.
— Leo

7

이 사실 때문에 xml에서 사용자 지정 글꼴을 사용하는 것은 좋지 않습니다. 즉, 메모리 누수를 방지하기 위해 프로그래밍 방식으로 수행해야합니다!


6
Ice Cream Sandwich에서 메모리 누수가 수정 된 것 같습니다.
— Michael Scheper 2014

2
메모리 누수를 방지하려면 TypedArray 메서드 recycle ()을 사용해야합니다.
— Abhinav Saxena

7

업데이트 : https://github.com/chrisjenx/Calligraphy 가 이에 대한 우수한 솔루션 인 것으로 보입니다.


어쩌면 당신은 할 수 삽입하는 반사를 사용 / 사용 가능한 글꼴의 정적 목록에 글꼴을 해킹 응용 프로그램을 만들 때? 나는 이것이 정말로, 정말로 나쁜 생각 이거나 이것이 훌륭한 해결책 이라면 다른 사람들의 피드백에 관심 이 있습니다. 그것은 극단 중 하나가 될 것 같습니다.

내 글꼴 패밀리 이름을 사용하여 시스템 서체 목록에 사용자 정의 서체를 삽입 한 다음 해당 사용자 정의 글꼴 패밀리 이름 ( "brush-script") 을 내 LG에서 작동하는 표준 TextView 의 android : FontFamily 값으로 지정 했습니다. Android 6.0을 실행하는 G4.

public class MyApplication extends android.app.Application
{
    @Override
    public void onCreate()
    {
        super.onCreate();

        Typeface font = Typeface.createFromAsset(this.getResources().getAssets(),"fonts/brush-script.ttf");
        injectTypeface("brush-script", font);
    }

    private boolean injectTypeface(String fontFamily, Typeface typeface)
    {
        try
        {
            Field field = Typeface.class.getDeclaredField("sSystemFontMap");
            field.setAccessible(true);
            Object fieldValue = field.get(null);
            Map<String, Typeface> map = (Map<String, Typeface>) fieldValue;
            map.put(fontFamily, typeface);
            return true;
        }
        catch (Exception e)
        {
            Log.e("Font-Injection", "Failed to inject typeface.", e);
        }
        return false;
    }
}

내 레이아웃에서

<TextView
    android:id="@+id/name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Fancy Text"
    android:fontFamily="brush-script"/>

저에게 적합하지 않습니다. 사용 방법을 자세히 설명해 주시겠습니까? MyApplication클래스를 호출해야 합니까 ?
— Dadan

@Yawz 애플리케이션에서 적어도 한 번은 injectTypeface 메서드를 호출해야합니다. 예외를 기록하면 세부 사항에 관심이 있습니다. 나는 Android 6.0을 실행하는 LG G4에서만 테스트했으며 (당시 자체 조사 중이 었음) 모든 버전의 Android에서 작동하지 않을 것으로 예상합니다.
— Ross Bradbury

lenova의 A7000 모델 - 그것은 일부 장치에없는 일 .. 제대로 작동 장치의 대부분을하지만 일부 장치는이의 font .. 내 테스트 장치에 동의하지 @RossBradbury
— 란 지트 쿠마르

업데이트 : github.com/chrisjenx/Calligraphy 는 우수한 솔루션입니다.
— Ross Bradbury 2011

4

자산에 글꼴 폴더를 만들고 필요한 모든 글꼴을 거기에 추가하십시오.

public class CustomTextView extends TextView {
    private static final String TAG = "TextView";

    public CustomTextView(Context context) {
        super(context);
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setCustomFont(context, attrs);
    }

    public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setCustomFont(context, attrs);
    }

    private void setCustomFont(Context ctx, AttributeSet attrs) {
        TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
        String customFont = a.getString(R.styleable.CustomTextView_customFont);
        setCustomFont(ctx, customFont);
        a.recycle();
    }

    public boolean setCustomFont(Context ctx, String fontName) {
        Typeface typeface = null;
        try {
            if(fontName == null){
                fontName = Constants.DEFAULT_FONT_NAME;
            }
            typeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/" + fontName);
        } catch (Exception e) {
            Log.e(TAG, "Unable to load typeface: "+e.getMessage());
            return false;
        }
        setTypeface(typeface);
        return true;
    }
}

attrs.xml 에 선언 가능한 추가

<declare-styleable name="CustomTextView">
      <attr name="customFont" format="string"/>
</declare-styleable>

그런 다음 customFont를 추가하십시오.

app:customFont="arial.ttf"

당신은 또한 여기에서 수행 된 스타일로 작업하기 위해 위의 클래스를 사용자 정의 할 수 있습니다. github.com/leok7v/android-textview-custom-fonts/blob/master/res/…
— AndroidGeek

4

나는 이것이 오래된 질문이라는 것을 알고 있지만 훨씬 더 쉬운 해결책을 찾았습니다.

먼저 평소와 같이 xml에서 TextView를 선언하십시오. 자산 폴더에 글꼴 (TTF 또는 TTC)을 넣습니다.

앱 \ src \ main \ assets \

그런 다음 onCreate 메서드에서 텍스트보기의 서체를 설정하면됩니다.

@Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_name);    

    TextView textView = findViewById(R.id.my_textView);
    Typeface typeface = Typeface.createFromAsset(getAssets(), "fontName.ttf");
    textView.setTypeface(typeface);
}

끝난.


1
질문은 프로그래밍 방식이 아닌 xml 파일 내에서 사용하도록 명시되어 있습니다.
— Gustavo Baiocchi Costa


0

xmlns : custom = "schemas.android.com/tools"대신; 다음을 사용해야합니다. xmlns : custom = "schemas.android.com/apk/res-auto"; 스타일링 가능한 속성을 사용하기 위해. 이 변경 사항을 적용했으며 현재 작동 중입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.