XMLを使用してAndroid TextViewでカスタムフォントを使用する


92

カスタムフォントファイルをassets / 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 16

他の人が言ったように、書道を使用してこれを実現できます。
mbonnin 2017年

この記事を確認してください。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書体(bolditalicなど)を考慮し、それをフォントに適用します(.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>

正解です。ただし、1つの質問:isInEditModeのときになぜ戻ったのですか?
Avi Shukron、2015

04-11 18:18:32.685 3506-3506 / com.example.demo E / AndroidRuntime:FATAL EXCEPTION:main Process:com.example.demo、PID:3506 android.view.InflateException:Binary XML file line#2:Error inflating class com.example.demo.libraries.LatoTextView at android.view.LayoutInflater.createView(LayoutInflater.java:620)at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:696)at android.view.LayoutInflater.inflate( LayoutInflater.java:469)at android.view.LayoutInflater.inflate(LayoutInflater.java:397)at ...
e-info128

。私はそれがカスタム書体を適用する処理方法を知っていないと思われるので(プレビューモード中のAndroid Studioでエラーを取得して保持するのでそこだ- @AvrahamShukron
themarshal

RelativeLayoutにxmlns:custom = " schemas.android.com/tools "を追加し、エラーはなくなりました。おかげで男
Naveedアフマド

1
@themarshalこんにちは:代わりののxmlns:カスタム=「schemas.android.com/toolsあなたが使用する必要がある『:のxmlns:カスタム=』schemas.android.com/apk/res-auto styleable属性を使用するために」。
Abhinav Saxena

28

これを行うコード例を次に示します。静的なfinal変数でフォントを定義しており、フォントファイルはアセットディレクトリにあります。

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 2016年

13

使用するフォントに属するカスタムTextViewを作成します。このクラスでは、静的mTypefaceフィールドを使用してタイプフェイスをキャッシュします(パフォーマンスを向上させるため)。

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"
        ... />

Javaクラス:

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

11

Activityは、作成された各ビューにコールバックを提供する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年間触れなかった。しかし、そうすべきです。理論的にはそれを妨げるものは何もありません。
レオ

7

この事実のため、xmlでカスタムフォントを使用する ことはお勧めできません。つまり、メモリリークを回避するためにプログラムで実行する必要があります。


6
メモリリークはIce Cream Sandwichで修正されたようです。
Michael Scheper 2014

2
TypedArrayメソッドrecycle()を使用して、メモリリークを回避する必要があります。
Abhinav Saxena

7

更新:https : //github.com/chrisjenx/Calligraphyはこれに対する優れたソリューションのようです。


たぶん、あなたはできる注入/利用可能なフォントの静的リストにあなたのフォントをハックするためにリフレクションを使用して、アプリケーションが作成されたとき?これが本当に、非常に悪い考えである場合、またはこれが優れた解決策である場合、他の人からのフィードバックに興味があります。これらの極端な例の1つになると思われます...

私のカスタム書体をシステム書体のリストに独自のフォントファミリ名で挿入し、そのカスタムフォントファミリ名( "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 2016年

@Yawzアプリケーションで少なくとも1回はinjectTypefaceメソッドを呼び出す必要があります。例外がログに記録される場合、詳細に興味があります。私はこれをAndroid 6.0を実行しているLG G4でのみテストしました(そのとき私は自分でいくつかの調査を行っていました)が、Androidのすべてのバージョンで動作するとは限りません。
ロスブラッドベリ

@RossBradbury一部のデバイスでは動作しません。.ほとんどのデバイスは正常に動作しますが、一部のデバイスはこのフォントファミリを受け入れません..テストしたデバイス-lenova a7000モデル
Ranjith Kumar

更新:github.com/chrisjenx/Calligraphyは優れたソリューションです。
ロスブラッドバリー

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

私はこれが古い質問であることを知っていますが、はるかに簡単な解決策を見つけました。

最初に、通常どおりTextViewをxmlで宣言します。フォント(TTFまたはTTC)をアセットフォルダに配置します

app \ 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.