programing tip

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

itbloger 2020. 9. 4. 07:00
반응형

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


내 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에서 할 수 없습니까 ?


짧은 대답 : 아니요. 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>

다음은이를 수행하는 예제 코드입니다. 정적 최종 변수에 글꼴이 정의되어 있고 글꼴 파일은 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);
    }

}

사용하려는 글꼴에 속하는 사용자 지정 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());

활동은 생성 된 각 뷰에 콜백을 제공하는 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"
  />

결과

여기에 이미지 설명 입력


Not a good idea to use custom fonts in xml due to this fact that is, you have to do it programmatically to avoid the memory leak!


UPDATE: https://github.com/chrisjenx/Calligraphy appears to be a superior solution to this.


Maybe you can use reflection to inject/hack your font into the static list of available fonts when your application is created? I am interested in feedback from others if this is a really, really bad idea or if this is a great solution — it seems it is going to be one of those extremes...

I was able to inject my custom typeface into the list of system typefaces with my own font family name, then specifying that custom font family name ("brush-script") as the value of android:FontFamily on a standard TextView worked on my LG G4 running Android 6.0.

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;
    }
}

In my layout

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

Create a fonts folder in assets and add all your required font's there.

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;
    }
}

and add a declarable in attrs.xml

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

and then add your customFont like

app:customFont="arial.ttf"

I know this is an old question, but i've found a much easier solution.

First declare your TextView in xml as usual. Put your font (TTF or TTC) in the asset folder

app\src\main\assets\

Then just set the typeface for your text view in your onCreate method.

@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);
}

Done.


가장 좋은 해결책은 (마지막으로) Google에서 도입 한 XML의 기본 사용자 정의 글꼴 기능을 사용하는 것입니다. 하지만 API 26을 타겟팅해야합니다. API 16 이상을 지원합니다.

https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml


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

참고 URL : https://stackoverflow.com/questions/9327053/using-custom-font-in-android-textview-using-xml

반응형