Android: Sie möchten benutzerdefinierte Schriftarten für die gesamte Anwendung und nicht für die Laufzeit festlegen

100

Ist es möglich, in jedem Steuerelement der Anwendung eine benutzerdefinierte Schriftart festzulegen? Und nicht unbedingt Laufzeit? (dh wenn möglich aus XML oder nur einmal für die gesamte Anwendung in der JAVA-Datei)

Ich kann die Schriftart für ein Steuerelement aus diesem Code festlegen.

public static void setFont(TextView textView) {
    Typeface tf = Typeface.createFromAsset(textView.getContext()
            .getAssets(), "fonts/BPreplay.otf");

    textView.setTypeface(tf);

}

Das Problem mit diesem Code ist, dass er für jedes Steuerelement aufgerufen werden sollte. Und ich möchte diese oder eine ähnliche Methode einmal aufrufen oder wenn möglich die Eigenschaft in XML setzen. Ist es möglich?

Prasham
quelle
6
Möglicherweise können Sie ein benutzerdefiniertes Steuerelement schreiben, indem Sie die Textansicht erweitern, und das Festlegen der Schriftart im Konstruktor kann eine Option sein. Anschließend können Sie dieses Steuerelement in der gesamten App anstelle Ihrer Textansicht verwenden. Um Speicherplatz zu sparen, können Sie das Laden von Ressourcen durch Verwendung eines statischen Schrifttyps verhindern.
Varun
@Varun: Nun, diese Idee kann meine Zeit sparen, aber ich muss jedes Steuerelement festlegen, und das Schreiben eines benutzerdefinierten Steuerelements für jedes ist länger als das Festlegen einer Schriftlauflaufzeit. Was denkst du? (Jedoch +1 für das Schreiben einer benutzerdefinierten Steuerung)
Prasham
Möglicherweise möchten Sie nur ein benutzerdefiniertes Steuerelement schreiben, das die Textansicht erweitert. Die einzige Änderung betrifft die Einstellung der Schriftart. Wenn Sie das cusotm-Steuerelement in Ihren Layoutdateien verwenden, müssen Sie dies nicht jedes Mal für jede Textansicht manuell tun, und Sie können trotzdem sicher sein, dass Sie die gewünschte Schriftart verwenden.
Varun
Was ist mit dem Schreiben eines Brauchs, VIEWanstatt ein custom text viewund ein custom button viewgetrennt zu schreiben ? Meine Anforderung gilt für jedes Steuerelement, und die Textansicht war nur ein Beispiel. Entschuldigung, ich habe vergessen, es zu erwähnen .. :-(
Prasham
1
Werfen Sie einen Blick auf satckoverflow Frage stackoverflow.com/questions/2711858/… es hilft Ihnen.
Ashwini

Antworten:

123

EDIT : Es ist also eine Weile her und ich möchte hinzufügen, was meiner Meinung nach der beste Weg ist, dies zu tun, und nicht weniger über XML!

Zunächst möchten Sie eine neue Klasse erstellen, die alle Ansichten überschreibt, die Sie anpassen möchten. (zB möchten Sie einen Button mit einer benutzerdefinierten Schrift? Erweitern Button). Machen wir ein Beispiel:

public class CustomButton extends Button {
    private final static int ROBOTO = 0;
    private final static int ROBOTO_CONDENSED = 1;

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

    public CustomButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        parseAttributes(context, attrs); //I'll explain this method later
    }

    public CustomButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        parseAttributes(context, attrs);
    }
}

Wenn Sie noch keines haben, fügen Sie unter ein XML-Dokument hinzu res/values/attrs.xmlund fügen Sie Folgendes hinzu:

<resources>
    <!-- Define the values for the attribute -->
    <attr name="typeface" format="enum">
        <enum name="roboto" value="0"/>
        <enum name="robotoCondensed" value="1"/>
    </attr>

    <!-- Tell Android that the class "CustomButton" can be styled, 
         and which attributes it supports -->
    <declare-styleable name="CustomButton">
        <attr name="typeface"/>
    </declare-styleable>
</resources>

Okay, wenn das aus dem Weg ist, kehren wir zu der parseAttributes()Methode von früher zurück:

private void parseAttributes(Context context, AttributeSet attrs) {
    TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.CustomButton);

    //The value 0 is a default, but shouldn't ever be used since the attr is an enum
    int typeface = values.getInt(R.styleable.CustomButton_typeface, 0);

    switch(typeface) {
        case ROBOTO: default:
            //You can instantiate your typeface anywhere, I would suggest as a 
            //singleton somewhere to avoid unnecessary copies
            setTypeface(roboto); 
            break;
        case ROBOTO_CONDENSED:
            setTypeface(robotoCondensed);
            break;
    }

    values.recycle();
}

Jetzt sind Sie fertig. Sie können für fast alles weitere Attribute hinzufügen (Sie können ein weiteres für typefaceStyle hinzufügen - fett, kursiv usw.), aber jetzt wollen wir sehen, wie es verwendet wird:

<?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/com.yourpackage.name"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.yourpackage.name.CustomButton
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me!"
        custom:typeface="roboto" />

</LinearLayout>

Die xmlns:customLinie kann wirklich alles sein, aber die Konvention ist die oben gezeigte. Was zählt ist, dass es einzigartig ist und deshalb der Paketname verwendet wird. Jetzt verwenden Sie nur das custom:Präfix für Ihre Attribute und das android:Präfix für Android-Attribute.

Eine letzte Sache: Wenn Sie dies in einem style ( res/values/styles.xml) verwenden möchten , sollten Sie die Zeile nicht hinzufügen xmlns:custom. Verweisen Sie einfach auf den Namen des Attributs ohne Präfix:

<style name="MyStyle>
    <item name="typeface">roboto</item>
</style>

                               (PREVIOUS ANSWER)

Verwenden einer benutzerdefinierten Schriftart in Android

Das sollte helfen. Grundsätzlich gibt es keine Möglichkeit, dies in XML zu tun, und soweit ich das beurteilen kann, gibt es keine einfachere Möglichkeit, dies in Code zu tun. Sie können jederzeit eine setLayoutFont () -Methode verwenden, die die Schriftart einmal erstellt und dann für jede setTypeface () ausführt. Sie müssen es nur jedes Mal aktualisieren, wenn Sie einem Layout ein neues Element hinzufügen. So etwas wie unten:

public void setLayoutFont() {
    Typeface tf = Typeface.createFromAsset(
        getBaseContext().getAssets(), "fonts/BPreplay.otf");
    TextView tv1 = (TextView)findViewById(R.id.tv1);
    tv1.setTypeface(tf);

    TextView tv2 = (TextView)findViewById(R.id.tv2);
    tv2.setTypeface(tf);

    TextView tv3 = (TextView)findViewById(R.id.tv3);
    tv3.setTypeface(tf);
}

EDIT : Also bin ich gerade dazu gekommen, so etwas selbst zu implementieren, und wie ich dazu kam, hat ich eine Funktion wie diese gemacht:

public static void setLayoutFont(Typeface tf, TextView...params) {
    for (TextView tv : params) {
        tv.setTypeface(tf);
    }
}

Verwenden Sie dann einfach diese Methode von onCreate () und übergeben Sie alle TextViews, die Sie aktualisieren möchten:

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/BPreplay.otf");
//find views by id...
setLayoutFont(tf, tv1, tv2, tv3, tv4, tv5);

EDIT 9/5/12:

Da dies immer noch Ansichten und Stimmen erhält, möchte ich eine viel bessere und vollständigere Methode hinzufügen:

Typeface mFont = Typeface.createFromAsset(getAssets(), "fonts/BPreplay.otf");
ViewGroup root = (ViewGroup)findViewById(R.id.myrootlayout);
setFont(root, mFont);

/*
 * Sets the font on all TextViews in the ViewGroup. Searches
 * recursively for all inner ViewGroups as well. Just add a
 * check for any other views you want to set as well (EditText,
 * etc.)
 */
public void setFont(ViewGroup group, Typeface font) {
    int count = group.getChildCount();
    View v;
    for(int i = 0; i < count; i++) {
        v = group.getChildAt(i);
        if(v instanceof TextView || v instanceof Button /*etc.*/)
            ((TextView)v).setTypeface(font);
        else if(v instanceof ViewGroup)
            setFont((ViewGroup)v, font);
    }
}

Wenn Sie ihm das Stammverzeichnis Ihres Layouts übergeben, wird rekursiv nach TextViewoder ButtonAnsichten (oder anderen, die Sie zu dieser if-Anweisung hinzufügen) in diesem Layout gesucht und die Schriftart festgelegt, ohne dass Sie sie anhand der ID angeben müssen. Dies setzt natürlich voraus, dass Sie die Schriftart für jede Ansicht festlegen möchten .

Kevin Coppock
quelle
1
Ich sehe keinen Unterschied in Ihrem Code und meinem Code, außer dass ich die Methode als Factory-Methode für die gesamte Anwendung verwende und Ihr Code für eine Aktivität geschrieben zu sein scheint. PS: Es ist wirklich seltsam, ein weiteres Objekt für eine schreibgeschützte Textansicht hinzuzufügen, um die Schriftart zu ändern. Off Topic: Android sollte wirklich einen Mechanismus einführen, um eine Schriftart aus dem Assests-Ordner abzurufen und in R aufzunehmen, damit sie zur Entwurfszeit geändert werden kann.)
Prasham
1
Ich denke, realistisch gesehen gibt es keinen großen Unterschied, außer dass Sie die Schrift nicht immer und immer wieder erstellen würden. Varuns Idee, nur eine statische Schrift zu verwenden, würde dasselbe bewirken.
Kevin Coppock
1
Sollte die letzte Zeile Ihres Beispielcodes setLayoutFont sein (tf, tv1, tv2, tv3, tv4, tv5); anstatt setTypeface (tf, tv1, tv2, tv3, tv4, tv5);?
Kyle Clegg
1
Solltest du nicht recycledas TypedArray values?
CorayThan
1
Wenn Sie Gradle verwenden, sollte der benutzerdefinierte Namespacexmlns:custom="http://schemas.android.com/apk/res-auto"
Jabari
93

Es gibt eine ziemlich einfache Möglichkeit, dies über XML zu tun. Sie müssen nur ein eigenes Widget erstellen, das TextView erweitert.

Erstellen Sie zunächst eine Datei in res / values ​​/ attrs.xml mit folgendem Inhalt:

<resources>
    <declare-styleable name="TypefacedTextView">
        <attr name="typeface" format="string" />
    </declare-styleable>
</resources>

Erstellen Sie anschließend Ihr benutzerdefiniertes Widget:

package your.package.widget;

public class TypefacedTextView extends TextView {

    public TypefacedTextView(Context context, AttributeSet attrs) {
        super(context, attrs);

        //Typeface.createFromAsset doesn't work in the layout editor. Skipping...
        if (isInEditMode()) {
            return;
        }

        TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.TypefacedTextView);
        String fontName = styledAttrs.getString(R.styleable.TypefacedTextView_typeface);
        styledAttrs.recycle();

        if (fontName != null) {
            Typeface typeface = Typeface.createFromAsset(context.getAssets(), fontName);
            setTypeface(typeface);
        }
    }

}

Wie Sie sehen können, liest der obige Code eine Schriftart in den Assets / Ordnern. In diesem Beispiel gehe ich davon aus, dass sich im Assets-Ordner eine Datei mit dem Namen "custom.ttf" befindet. Verwenden Sie zuletzt das Widget in den XMLs:

<your.package.widget.TypefacedTextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:your_namespace="http://schemas.android.com/apk/res/your.package"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Custom fonts in XML are easy"
    android:textColor="#FFF"
    android:textSize="14dip"
    your_namespace:typeface="custom.ttf" />

Hinweis: Ihre benutzerdefinierte Schriftart wird im Layout-Editor von Eclipse nicht angezeigt. Deshalb habe ich den isInEditMode()Scheck gestellt. Wenn Sie jedoch Ihre App ausführen, funktioniert die benutzerdefinierte Schriftart wie ein Zauber.

Ich hoffe es hilft!

Leocadiotin
quelle
Ich habe dies nicht versucht, aber ich habe ein benutzerdefiniertes Steuerelement erstellt, indem ich die TextViewKlasse erweitert habe. Stellen typefaceSie das ein und verwenden Sie das benutzerdefinierte Steuerelement im Layout, wie wir es normalerweise tun, und es hat bei mir funktioniert ... Es war jedoch einfach, dass das obige ...
Mahendra Liya
1
Ich habe genau das getan, was du gesagt hast. Der einzige Unterschied besteht darin, dass ich diese Komponente wiederverwendbar gemacht habe, da in der Frage gefragt wird, wie dies über XML erfolgen soll. Es gibt in der Tat einen Weg, dies über XML zu tun, und das ist der Weg, dies zu tun :)
Leocadiotin
Sehr einfach zu integrierender Code. Für mich geht das. Vielen Dank.
Durai
1
Dies sollte die akzeptierte Antwort sein. Schön geschrieben. Vielen Dank!
Reaz Murshed
1
Amesome, @DominikSuszczewicz! Können Sie bitte den Code teilen, damit ich die Antwort aktualisieren kann?
Leocadiotin
15

Beispiel für TextView mit Roboto-Schrift:

attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

<declare-styleable name="RobotoTextView">
    <attr name="typeface"/>
</declare-styleable>

<attr name="typeface" format="enum">
    <enum name="roboto_thin" value="0"/>
    <enum name="roboto_thin_italic" value="1"/>
    <enum name="roboto_light" value="2"/>
    <enum name="roboto_light_italic" value="3"/>
    <enum name="roboto_regular" value="4"/>
    <enum name="roboto_italic" value="5"/>
    <enum name="roboto_medium" value="6"/>
    <enum name="roboto_medium_italic" value="7"/>
    <enum name="roboto_bold" value="8"/>
    <enum name="roboto_bold_italic" value="9"/>
    <enum name="roboto_black" value="10"/>
    <enum name="roboto_black_italic" value="11"/>
    <enum name="roboto_condensed" value="12"/>
    <enum name="roboto_condensed_italic" value="13"/>
    <enum name="roboto_condensed_bold" value="14"/>
    <enum name="roboto_condensed_bold_italic" value="15"/>
</attr>

</resources>

RobotoTextView.java:

public class RobotoTextView extends TextView {

/*
 * Permissible values ​​for the "typeface" attribute.
 */
private final static int ROBOTO_THIN = 0;
private final static int ROBOTO_THIN_ITALIC = 1;
private final static int ROBOTO_LIGHT = 2;
private final static int ROBOTO_LIGHT_ITALIC = 3;
private final static int ROBOTO_REGULAR = 4;
private final static int ROBOTO_ITALIC = 5;
private final static int ROBOTO_MEDIUM = 6;
private final static int ROBOTO_MEDIUM_ITALIC = 7;
private final static int ROBOTO_BOLD = 8;
private final static int ROBOTO_BOLD_ITALIC = 9;
private final static int ROBOTO_BLACK = 10;
private final static int ROBOTO_BLACK_ITALIC = 11;
private final static int ROBOTO_CONDENSED = 12;
private final static int ROBOTO_CONDENSED_ITALIC = 13;
private final static int ROBOTO_CONDENSED_BOLD = 14;
private final static int ROBOTO_CONDENSED_BOLD_ITALIC = 15;
/**
 * List of created typefaces for later reused.
 */
private final static SparseArray<Typeface> mTypefaces = new SparseArray<Typeface>(16);

/**
 * Simple constructor to use when creating a view from code.
 *
 * @param context The Context the view is running in, through which it can
 *                access the current theme, resources, etc.
 */
public RobotoTextView(Context context) {
    super(context);
}

/**
 * Constructor that is called when inflating a view from XML. This is called
 * when a view is being constructed from an XML file, supplying attributes
 * that were specified in the XML file. This version uses a default style of
 * 0, so the only attribute values applied are those in the Context's Theme
 * and the given AttributeSet.
 * <p/>
 * <p/>
 * The method onFinishInflate() will be called after all children have been
 * added.
 *
 * @param context The Context the view is running in, through which it can
 *                access the current theme, resources, etc.
 * @param attrs   The attributes of the XML tag that is inflating the view.
 * @see #RobotoTextView(Context, AttributeSet, int)
 */
public RobotoTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    parseAttributes(context, attrs);
}

/**
 * Perform inflation from XML and apply a class-specific base style. This
 * constructor of View allows subclasses to use their own base style when
 * they are inflating.
 *
 * @param context  The Context the view is running in, through which it can
 *                 access the current theme, resources, etc.
 * @param attrs    The attributes of the XML tag that is inflating the view.
 * @param defStyle The default style to apply to this view. If 0, no style
 *                 will be applied (beyond what is included in the theme). This may
 *                 either be an attribute resource, whose value will be retrieved
 *                 from the current theme, or an explicit style resource.
 * @see #RobotoTextView(Context, AttributeSet)
 */
public RobotoTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    parseAttributes(context, attrs);
}

/**
 * Parse the attributes.
 *
 * @param context The Context the view is running in, through which it can access the current theme, resources, etc.
 * @param attrs   The attributes of the XML tag that is inflating the view.
 */
private void parseAttributes(Context context, AttributeSet attrs) {
    TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.RobotoTextView);

    int typefaceValue = values.getInt(R.styleable.RobotoTextView_typeface, 0);
    values.recycle();

    setTypeface(obtaintTypeface(context, typefaceValue));
}

/**
 * Obtain typeface.
 *
 * @param context       The Context the view is running in, through which it can
 *                      access the current theme, resources, etc.
 * @param typefaceValue values ​​for the "typeface" attribute
 * @return Roboto {@link Typeface}
 * @throws IllegalArgumentException if unknown `typeface` attribute value.
 */
private Typeface obtaintTypeface(Context context, int typefaceValue) throws IllegalArgumentException {
    Typeface typeface = mTypefaces.get(typefaceValue);
    if (typeface == null) {
        typeface = createTypeface(context, typefaceValue);
        mTypefaces.put(typefaceValue, typeface);
    }
    return typeface;
}

/**
 * Create typeface from assets.
 *
 * @param context       The Context the view is running in, through which it can
 *                      access the current theme, resources, etc.
 * @param typefaceValue values ​​for the "typeface" attribute
 * @return Roboto {@link Typeface}
 * @throws IllegalArgumentException if unknown `typeface` attribute value.
 */
private Typeface createTypeface(Context context, int typefaceValue) throws IllegalArgumentException {
    Typeface typeface;
    switch (typefaceValue) {
        case ROBOTO_THIN:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Thin.ttf");
            break;
        case ROBOTO_THIN_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-ThinItalic.ttf");
            break;
        case ROBOTO_LIGHT:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Light.ttf");
            break;
        case ROBOTO_LIGHT_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-LightItalic.ttf");
            break;
        case ROBOTO_REGULAR:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Regular.ttf");
            break;
        case ROBOTO_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Italic.ttf");
            break;
        case ROBOTO_MEDIUM:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Medium.ttf");
            break;
        case ROBOTO_MEDIUM_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-MediumItalic.ttf");
            break;
        case ROBOTO_BOLD:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Bold.ttf");
            break;
        case ROBOTO_BOLD_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldItalic.ttf");
            break;
        case ROBOTO_BLACK:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Black.ttf");
            break;
        case ROBOTO_BLACK_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BlackItalic.ttf");
            break;
        case ROBOTO_CONDENSED:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Condensed.ttf");
            break;
        case ROBOTO_CONDENSED_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-CondensedItalic.ttf");
            break;
        case ROBOTO_CONDENSED_BOLD:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldCondensed.ttf");
            break;
        case ROBOTO_CONDENSED_BOLD_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldCondensedItalic.ttf");
            break;
        default:
            throw new IllegalArgumentException("Unknown `typeface` attribute value " + typefaceValue);
    }
    return typeface;
}

}

Anwendungsbeispiel:

<your.package.widget.RobotoTextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:typeface="roboto_thin"
                android:textSize="22sp"
                android:text="Roboto Thin"/>

Ressourcen: Roboto & Noto-Schriftarten

e.shishkin
quelle
Gibt es eine Möglichkeit, diese Lösung zu verwenden, ohne die IDs von Schriftarten in der Java-Klasse zu korrigieren? Vielleicht lesen Sie diese letzten Felder aus enum attrs .. private final static int ROBOTO_THIN = 0; private final static int ROBOTO_THIN_ITALIC = 1; private final static int ROBOTO_LIGHT = 2; ...
Arthur Melo
3

Es ist zu spät, aber es hilft dem anderen, den
ich erstellt habe. CustomTextView hat ein Attribut namens typeFace und es behebt Probleme mit Speicherverlusten beim Laden von Schriftarten ohne Caching

Erstens eine FontsKlasse, die die Schriftarten nur einmal aus Assets lädt

 import android.content.Context;
import android.graphics.Typeface;

import java.util.Hashtable;

/**
 * Created by tonyhaddad on 7/19/15.
 */
public class Fonts {
    private Context context;

    public Fonts(Context context) {
        this.context = context;
    }
    private static Hashtable<String, Typeface> sTypeFaces = new Hashtable<String, Typeface>(
            4);
    public static Typeface getTypeFace(Context context, String fileName) {
        Typeface tempTypeface = sTypeFaces.get(fileName);

        if (tempTypeface == null) {
            String fontPath=null;
            if(fileName=="metabold")
                fontPath ="fonts/Meta-Bold.ttf";

            else if(fileName=="metanormal")
                fontPath="fonts/Meta-Normal.ttf";
            else if(fileName=="gsligh")
                fontPath="fonts/gesslight.ttf";
            else if(fileName=="bold")
                fontPath="fonts/Lato-Bold.ttf";
            else if(fileName=="rcr")
                fontPath="fonts/RobotoCondensed-Regular.ttf";

            else if(fileName=="mpr")
                fontPath="fonts/MyriadPro-Regular.otf";
            else if(fileName=="rr")
                fontPath="fonts/Roboto-Regular.ttf";

            tempTypeface = Typeface.createFromAsset(context.getAssets(), fontPath);
            sTypeFaces.put(fileName, tempTypeface);
        }

        return tempTypeface;
    }
}

Dann müssen Sie ein benutzerdefiniertes Attribut in der Datei attrs.xml hinzufügen

<declare-styleable name="CustomFontTextView">
        <attr name="typeFace" format="string" />

    </declare-styleable>

dann benutzerdefinierte Klasse

 package package_name;

/**
 * Created by tonyhaddad on 8/26/15.
 */

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;

import package_name.R;

public class CustomFontTextView extends TextView {

    String typeFace;


    public CustomFontTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        if (isInEditMode()) {
            return;
        }
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.CustomFontTextView,
                0, 0);
        try {
            typeFace = a.getString(0);
        } finally {
            a.recycle();
        }

        if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
        {
            Typeface tf = Fonts.getTypeFace(context, typeFace);
            setTypeface(tf);
        }
        init();
    }

    public CustomFontTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        if (isInEditMode()) {
            return;
        }
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.CustomFontTextView,
                0, 0);
        try {
            typeFace = a.getString(0);
        } finally {
            a.recycle();
        }

        if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
        {
            Typeface tf = Fonts.getTypeFace(context, typeFace);
            setTypeface(tf);
        }

        init();
    }

    public CustomFontTextView(Context context) {
        super(context);



        if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
        {
            Typeface tf = Fonts.getTypeFace(context, typeFace);
            setTypeface(tf);
        }
        init();
    }


    private void init() {

    }

    public String getTypeFace() {
        return typeFace;
    }

    public void setTypeFace(String typeFace) {
        this.typeFace = typeFace;
        invalidate();
        requestLayout();
    }
}

und schließlich die Textansicht hinzufügen

  <package_name.CustomFontTextView
            xmlns:custom="http://schemas.android.com/apk/res-auto/package_name"
            android:id="@+id/txt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="41dp"
            android:gravity="center_vertical"
            android:text="text"
            android:textColor="#000"
            android:textSize="23sp"
            custom:typeFace="metanormal"/>

Sie können die Schriftart auch programmgesteuert mit der setTypeFace-Methode ändern.
Sie können auch den benutzerdefinierten Namespace in Ihr übergeordnetes Layout verschieben, wenn Sie in dieser Ansicht mehrere verwenden möchten

Viel Spaß beim Codieren :)

Antwan
quelle
einfache Antwort.
eyadMhanna
2

Die folgende Methode, die in onCreate () aufgerufen und Ihre äußerste ViewGroup übergeben wurde, funktioniert für alles außer Text, der dynamisch erstellt wird (dh dynamische Listen, Warnungen usw.). Eine einfache Möglichkeit, die äußerste ViewGroup zu erhalten, besteht darin, getRootView für eine Ihrer Ansichten zu verwenden.

public void onCreate(Bundle savedInstanceState){
    //onCreate code...
    EditText text = (EditText) findViewById(R.id.editText1);
    setTypeFaceForViewGroup((ViewGroup) text.getRootView());
}

private void setTypeFaceForViewGroup(ViewGroup vg){

    for (int i = 0; i < vg.getChildCount(); i++) {

            if (vg.getChildAt(i) instanceof ViewGroup)
                setTypeFaceForViewGroup((ViewGroup) vg.getChildAt(i));

            else if (vg.getChildAt(i) instanceof TextView)
                ((TextView) vg.getChildAt(i)).setTypeface(Typeface.createFromAsset(getAssets(), "fonts/Your_Font.ttf"));

    }

}

Dies sollte auch für dynamische Inhalte funktionieren. Sie müssen sie nur aufrufen und alles, was Sie erstellt haben, direkt nach der Erstellung übergeben (ich habe dies jedoch nicht getestet).

Um Speicherplatz zu sparen, möchten Sie die Schrift wahrscheinlich zu einer statischen Variablen machen, anstatt jedes Mal eine neue zu erstellen, wenn die Schleife wie hier ausgeführt wird.

Chris
quelle
Ich empfehle diese Lösung nicht, da Sie für jedes Element, auf das Sie sie anwenden möchten, eine neue Instanz derselben Schriftart erstellen. Dies kann zu Speicherproblemen führen.
Fehler
Das wird in meiner Notiz am Ende behandelt.
Chris
2

Wenn Sie nach einer allgemeineren programmatischen Lösung suchen, habe ich eine statische Klasse erstellt, mit der Sie die Schriftart einer gesamten Ansicht festlegen können (Aktivitäts-Benutzeroberfläche). Beachten Sie, dass ich mit Mono (C #) arbeite, Sie es jedoch problemlos mit Java implementieren können.

Sie können dieser Klasse ein Layout oder eine bestimmte Ansicht übergeben, die Sie anpassen möchten. Wenn Sie sehr effizient sein möchten, können Sie es mithilfe des Singleton-Musters implementieren.

public static class AndroidTypefaceUtility 
{
    static AndroidTypefaceUtility()
    {
    }
    //Refer to the code block beneath this one, to see how to create a typeface.
    public static void SetTypefaceOfView(View view, Typeface customTypeface)
    {
    if (customTypeface != null && view != null)
    {
            try
            {
                if (view is TextView)
                    (view as TextView).Typeface = customTypeface;
                else if (view is Button)
                    (view as Button).Typeface = customTypeface;
                else if (view is EditText)
                    (view as EditText).Typeface = customTypeface;
                else if (view is ViewGroup)
                    SetTypefaceOfViewGroup((view as ViewGroup), customTypeface);
                else
                    Console.Error.WriteLine("AndroidTypefaceUtility: {0} is type of {1} and does not have a typeface property", view.Id, typeof(View));
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine("AndroidTypefaceUtility threw:\n{0}\n{1}", ex.GetType(), ex.StackTrace);
                    throw ex;
                }
            }
            else
            {
                Console.Error.WriteLine("AndroidTypefaceUtility: customTypeface / view parameter should not be null");
            }
        }

        public static void SetTypefaceOfViewGroup(ViewGroup layout, Typeface customTypeface)
        {
            if (customTypeface != null && layout != null)
            {
                for (int i = 0; i < layout.ChildCount; i++)
                {
                    SetTypefaceOfView(layout.GetChildAt(i), customTypeface);
                }
            }
            else
            {
                Console.Error.WriteLine("AndroidTypefaceUtility: customTypeface / layout parameter should not be null");
            }
        }

    }

In Ihrer Aktivität müssen Sie ein Schriftobjekt erstellen. Ich erstelle meine in OnCreate () mit einer .ttf-Datei in meinem Verzeichnis Resources / Assets /. Stellen Sie sicher, dass die Datei in ihren Eigenschaften als Android-Asset markiert ist.

protected override void OnCreate(Bundle bundle)
{               
    ...
    LinearLayout rootLayout = (LinearLayout)FindViewById<LinearLayout>(Resource.Id.signInView_LinearLayout);
    Typeface allerTypeface = Typeface.CreateFromAsset(base.Assets,"Aller_Rg.ttf");
    AndroidTypefaceUtility.SetTypefaceOfViewGroup(rootLayout, allerTypeface);
}
JCKortlang
quelle
2

Leider bietet Android nicht die schnelle, einfache und saubere Möglichkeit, die Schriftart für Ihre gesamte App zu ändern. Aber kürzlich habe ich mich mit dieser Angelegenheit befasst und einige Tools erstellt, mit denen Sie die Schriftart ohne Codierung ändern können (Sie können dies alles über XML, Stile und sogar Textdarstellungen tun). Sie basieren auf ähnlichen Lösungen wie in den anderen Antworten hier, ermöglichen jedoch weitaus mehr Flexibilität. Sie können alles darüber in diesem Blog lesen und das Github-Projekt hier sehen .

Hier ist ein Beispiel für die Anwendung dieser Tools. Fügen Sie alle Ihre Schriftdateien ein assets/fonts/. Deklarieren Sie diese Schriftarten dann in einer XML-Datei (z. B. res/xml/fonts.xml) und laden Sie diese Datei frühzeitig in Ihre App mit TypefaceManager.initialize(this, R.xml.fonts);(z. B. im onCreate Ihrer Anwendungsklasse). Die XML-Datei sieht folgendermaßen aus:

<?xml version="1.0" encoding="utf-8"?>
<familyset>

    <!-- Some Font. Can be referenced with 'someFont' or 'aspergit' -->
    <family>
        <nameset>
            <name>aspergit</name>
            <name>someFont</name>
        </nameset>
        <fileset>
            <file>Aspergit.ttf</file>
            <file>Aspergit Bold.ttf</file>
            <file>Aspergit Italic.ttf</file>
            <file>Aspergit Bold Italic.ttf</file>
        </fileset>
    </family>

    <!-- Another Font. Can be referenced with 'anotherFont' or 'bodoni' -->
    <family>
        <nameset>
            <name>bodoni</name>
            <name>anotherFont</name>
        </nameset>
        <fileset>
            <file>BodoniFLF-Roman.ttf</file>
            <file>BodoniFLF-Bold.ttf</file>
        </fileset>
    </family>

</familyset>

Jetzt können Sie diese Schriftarten in Ihrem Stil oder in XML verwenden (vorausgesetzt, Sie verwenden die oben genannten Tools), indem Sie das benutzerdefinierte UI-Element com.innovattic.font.FontTextViewin Ihrem XML-Layout verwenden. Unten sehen Sie, wie Sie eine Schriftart auf alle Texte in Ihrer gesamten App anwenden können, indem Sie einfach Folgendes bearbeiten res/values/styles.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">

    <!-- Application theme -->
    <!-- Use a different parent if you don't want Holo Light -->
    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
        <item name="android:textViewStyle">@style/MyTextViewStyle</item>
    </style>

    <!-- Style to use for ALL text views (including FontTextView) -->
    <!-- Use a different parent if you don't want Holo Light -->
    <style name="MyTextViewStyle" parent="@android:style/Widget.Holo.Light.TextView">
        <item name="android:textAppearance">@style/MyTextAppearance</item>
    </style>

    <!-- Text appearance to use for ALL text views (including FontTextView) -->
    <!-- Use a different parent if you don't want Holo Light -->
    <style name="MyTextAppearance" parent="@android:style/TextAppearance.Holo">
        <!-- Alternatively, reference this font with the name "aspergit" -->
        <!-- Note that only our own TextView's will use the font attribute -->
        <item name="flFont">someFont</item>
        <item name="android:textStyle">bold|italic</item>
    </style>

    <!-- Alternative style, maybe for some other widget -->
    <style name="StylishFont">
        <item name="flFont">anotherFont</item>
        <item name="android:textStyle">normal</item>
    </style>

</resources>

Mit der Begleitung res/layout/layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <!-- This text view is styled with the app theme -->
    <com.innovattic.font.FontTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This uses my font in bold italic style" />

    <!-- This text view is styled here and overrides the app theme -->
    <com.innovattic.font.FontTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:flFont="anotherFont"
        android:textStyle="normal"
        android:text="This uses another font in normal style" />

    <!-- This text view is styled with a style and overrides the app theme -->
    <com.innovattic.font.FontTextView
        style="@style/StylishFont"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This also uses another font in normal style" />

</LinearLayout>

Vergessen Sie nicht, das Thema in Ihrem Android-Manifest anzuwenden.

Jelle Fresen
quelle
2

Ich möchte der großartigen Lösung von eine Notiz hinzufügen leocadiotine. Es ist perfekt, aber wenn Sie diese benutzerdefinierte Textansicht verwenden, wird die Anwendung oft verlangsamt, da sie bei jeder Erstellung einer Textansicht auf die Assets zugreifen muss. Ich schlage vor, etwas wie das View Holder patternin der zu verwenden Adapters, ich schrieb ein Beispiel:

public class Fonts {

    private static final Map<String, Typeface> typefaces = new HashMap<String, Typeface>();

    public static Typeface getTypeface(Context ctx, String fontName) {
        Typeface typeface = typefaces.get(fontName);
        if (typeface == null) {
            typeface = Typeface.createFromAsset(ctx.getAssets(), fontName);
            typefaces.put(fontName, typeface);
        }
        return typeface;
    } 
}

Auf diese Weise greift die Anwendung nur einmal pro Asset auf die Assets zu und speichert sie für weitere Anforderungen im Speicher.

Emaborsa
quelle
0

Ich weiß nicht, ob es die gesamte App ändert, aber ich habe es geschafft, einige Komponenten zu ändern, die sonst nicht geändert werden könnten:

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Lucida Sans Unicode.ttf");
Typeface.class.getField("DEFAULT").setAccessible(true);
Typeface.class.getField("DEFAULT_BOLD").setAccessible(true);
Typeface.class.getField("DEFAULT").set(null, tf);
Typeface.class.getField("DEFAULT_BOLD").set(null, tf);
Richard
quelle
@richard, ich möchte die benutzerdefinierte Schriftart entsprechend dem Gebietsschema festlegen. Zum Beispiel möchte ich die Arial-TTF festlegen, wann immer wir das englische Gebietsschema verwenden, und die gotische TTF festlegen, wenn ich die koreanische Loacale verwende
Dwivedi Ji
0

Ich habe Schritt für Schritt Informationen unter diesem Link gefunden: https://github.com/jaydipumaretiya/CustomTypeface/

Es gibt viele Möglichkeiten, die Schrift in Android korrekt zu verwenden. Sie müssen Ihre Schriftdatei im Assets-Ordner direkt unter Ihrem Hauptordner ablegen und können sie zur Laufzeit verwenden.

Eine andere einfachste Möglichkeit ist die Verwendung der Standardbibliothek zum Festlegen der Schriftart in Ihrer XML-Datei. Ich habe diese benutzerdefinierte Schriftbibliothek vorgezogen, um die Schrift auf TextView, EditText, Button, CheckBox, RadioButton und AutoCompleteTextView und andere Wedgets in Android zu setzen.

Mehul Rakholiya
quelle
Der Github-Link funktioniert nicht.
Thomas vor
0

Android 8.0 (API-Level 26) führt eine neue Funktion ein: Schriftarten in XML. Sie können eine Schriftfamiliendatei erstellen und in styles.xml festlegen.

Führen Sie im Android Studio die folgenden Schritte aus, um Schriftarten als Ressourcen hinzuzufügen:

1.Klicken Sie mit der rechten Maustaste auf den Ordner res und gehen Sie zu Neu> Android-Ressourcenverzeichnis. Das Fenster Neues Ressourcenverzeichnis wird angezeigt.

2.Wählen Sie in der Liste Ressourcentyp die Schriftart aus und klicken Sie auf OK. Hinweis: Der Name des Ressourcenverzeichnisses muss Schriftart sein.

3. Fügen Sie Ihre Schriftdateien in den Schriftordner ein.

Führen Sie die folgenden Schritte aus, um eine Schriftfamilie zu erstellen:

1.Klicken Sie mit der rechten Maustaste auf den Schriftartenordner und gehen Sie zu Neu> Schriftartressourcendatei. Das Fenster Neue Ressourcendatei wird angezeigt.

2.Geben Sie den Dateinamen ein und klicken Sie auf OK. Die neue XML-Schriftartressource wird im Editor geöffnet.

3. Schließen Sie jede Schriftartdatei, jeden Stil und jedes Gewichtsattribut in das Element ein. Das folgende XML veranschaulicht das Hinzufügen von Schriftartenattributen zur XML-Schriftartressource:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
    <font
        android:fontStyle="normal"
        android:fontWeight="400"
        android:font="@font/lobster_regular" />
    <font
        android:fontStyle="italic"
        android:fontWeight="400"
        android:font="@font/lobster_italic" />
</font-family>

Hinzufügen von Schriftarten zum Stil

Öffnen Sie die Datei styles.xml und setzen Sie das Attribut fontFamily auf die Schriftartdatei, auf die Sie zugreifen möchten.

 <style name="customfontstyle" parent="@android:style/TextAppearance.Small">
    <item name="android:fontFamily">@font/lobster</item>
</style>

Quelle: Schriftarten in XML

Android-Entwickler
quelle