it-swarm.com.de

Verwenden einer benutzerdefinierten Schriftart in Android TextView mit XML

Ich habe eine benutzerdefinierte Schriftartdatei zu meinem Ordner mit den Assets/Schriftarten hinzugefügt. Wie verwende ich es aus meinem XML? 

Ich kann es aus dem Code wie folgt verwenden:

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

Kann ich es nicht aus XML mit einem Android:typeface="/fonts/Molot.otf"-Attribut machen?

90
npanigrahy

Kurze Antwort: Nein. Android bietet keine integrierte Unterstützung für das Anwenden benutzerdefinierter Schriftarten auf Text-Widgets über XML.

Es gibt jedoch eine Problemumgehung, die nicht sehr schwer zu implementieren ist.

Zuerst

Sie müssen Ihr eigenes Stylable definieren. Öffnen Sie im Ordner/res/values ​​die Datei attrs.xml und erstellen Sie sie, und fügen Sie ein deklarationsstilfähiges Objekt hinzu:

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

Zweite

Angenommen, Sie möchten dieses Widget häufig verwenden, sollten Sie einen einfachen Cache für die geladenen Typeface-Objekte einrichten, da das Laden der Objekte aus dem Arbeitsspeicher zeitaufwändig sein kann. So etwas wie:

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

Mit dieser können Sie .ttc-Dateierweiterungen verwenden, es wurde jedoch kein Test durchgeführt.

Dritte

Erstellen Sie eine neue Klasse, die TextView Unterklassen. In diesem Beispiel wird die definierte XML-Schriftart (bold, italic usw.) berücksichtigt und auf die Schriftart angewendet (vorausgesetzt, Sie verwenden eine .ttc-Datei).

/**
 * 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));
            }
        }
    }
}

Endlich

Ersetzen Sie die Instanzen von TextView in Ihrem XML durch den vollständig qualifizierten Klassennamen. Deklarieren Sie Ihren benutzerdefinierten Namespace genauso wie Sie den Android-Namespace. Beachten Sie, dass "typefaceAsset" auf eine .ttf- oder .ttc-Datei verweisen sollte, die sich in Ihrem Verzeichnis/assets befindet.

<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>
43
themarshal

Hier ist ein Beispielcode, der dies tut. Ich habe die Schriftart in einer statischen finalen Variablen definiert und die Schriftartdatei befindet sich im Assets-Verzeichnis.

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

}
27
Stephan Wiesner

Activity implementiert LayoutInflater.Factory2, das Callbacks für jede erstellte View ..__ bereitstellt. Es ist möglich, die TextView mit einem benutzerdefinierten Schriftfamilienattribut zu formatieren, die Schriftarten bei Bedarf zu laden und setTypeface automatisch für instantiierte Textansichten aufzurufen.

Aufgrund der architektonischen Beziehung zwischen Inflater-Instanzen im Verhältnis zu Aktivitäten und Windows ist es am einfachsten, benutzerdefinierte Schriftarten in Android zu verwenden, indem geladene Schriftarten auf Anwendungsebene zwischengespeichert werden.

Die Beispielcodebasis ist hier:

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

führt in

enter image description here

11
Leo

Erstellen Sie Ihr benutzerdefiniertes TextView, das zu der Schriftart gehört, die Sie verwenden möchten. In dieser Klasse verwende ich ein statisches mTypeface-Feld zum Zwischenspeichern der Schrift (zur Verbesserung der Leistung).

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

}

In XML-Datei:

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

In Java-Klasse:

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

UPDATE: https://github.com/chrisjenx/Calligraphy scheint eine .__ zu sein. überlegene Lösung dafür.


Vielleicht können Sie Reflection verwenden, um Ihre Schrift in die statische Liste der verfügbaren Schriftarten zu hacken/zu hacken, wenn Ihre Anwendung erstellt wird? Ich bin an Feedback von anderen interessiert, wenn dies eine wirklich, wirklich schlechte Idee ist oder wenn dies eine großartige Lösung ist - es scheint, dass es eines dieser Extreme wird ...

Ich konnte meine benutzerdefinierte Schriftart in die Liste der Systemschriftarten mit meinem eigenen Schriftfamiliennamen einfügen und dann den Namen der benutzerdefinierten Schriftfamilie ("Pinsel-Skript") als Wert von Android: FontFamily in einer Standard-Textansicht angeben arbeitete auf meinem LG G4 mit 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 meinem Layout

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

Es ist keine gute Idee, benutzerdefinierte Schriftarten in xml zu verwenden, weil diese Tatsache .

7
type-a1pha

Ich weiß, das ist eine alte Frage, aber ich habe eine wesentlich einfachere Lösung.

Zuerst deklarieren Sie Ihren TextView wie gewohnt in xml ..__ Legen Sie Ihre Schriftart (TTF oder TTC) im Asset-Ordner ab

app\src\main\assets \

Dann legen Sie einfach die Schriftart für Ihre Textansicht in Ihrer onCreate-Methode fest.

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

Erledigt.

3
Oiproks

Erstellen Sie einen Schriftartenordner in Assets und fügen Sie dort alle erforderlichen Schriftarten hinzu.

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

und fügen Sie eine deklarationsfähige Datei in attrs.xml ein.

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

und fügen Sie dann Ihr customFont hinzu

app:customFont="arial.ttf"
1
Xar E Ahmer

Die beste Lösung ist, (endlich) von Google eine native Funktion für benutzerdefinierte Schriftarten in XML einzuführen. Sie müssen jedoch API 26 als Ziel festlegen. Sie unterstützt API 16+

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

0
Kirill Karmazin

anstelle von xmlns: custom = "schemas.Android.com/tools"; Sie sollten Folgendes verwenden: xmlns: custom = "schemas.Android.com/apk/res-auto"; Um styleable Attribute zu verwenden, habe ich diese Änderung vorgenommen und es funktioniert jetzt. 

0
Abhinav Saxena