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.