Verwenden einer benutzerdefinierten Schriftart in Android


111

Ich möchte eine benutzerdefinierte Schriftart für meine Android-Anwendung verwenden, die ich erstelle.
Ich kann die Schriftart jedes Objekts von Code aus individuell ändern, aber ich habe Hunderte davon.

So,

  • Gibt es eine Möglichkeit, dies aus dem XML heraus zu tun? [Festlegen einer benutzerdefinierten Schriftart]
  • Gibt es eine Möglichkeit, dies aus Code an einer Stelle zu tun, um zu sagen, dass die gesamte Anwendung und alle Komponenten die benutzerdefinierte Schriftart anstelle der Standardschrift verwenden sollten?

stackoverflow.com/questions/5541058/… Schauen Sie sich diesen Beitrag an Ich habe den vollständigen Code hier zu diesem Problem veröffentlicht
Manish Singla

Sie können statische Variablen für Ihre Hauptaktivität verwenden, um Verweise auf die eingebetteten Schriftarten zu speichern. Dies würde dazu führen, dass es einen dauerhaften Satz von Schriftarten gibt, die von GC nicht erfasst werden.
Jacksonkr

Fabrikmethode. Oder eine Methode, die Ihre Ansicht aufnimmt und alle Einstellungen für Schriftart und Schrift festlegt.
Mtmurdock

Mit der neuen Unterstützungsbibliothek 26 können Sie jetzt Schriftarten in XML verwenden. Hier ist, wie es Schriften in XML
Vinicius Silva

Antworten:


80

Gibt es eine Möglichkeit, dies aus dem XML heraus zu tun?

Nein Entschuldigung. Sie können die integrierten Schriftarten nur über XML angeben.

Gibt es eine Möglichkeit, dies aus Code an einer Stelle zu tun, um zu sagen, dass die gesamte Anwendung und alle Komponenten die benutzerdefinierte Schriftart anstelle der Standardschrift verwenden sollten?

Nicht dass ich wüsste.

Heutzutage gibt es dafür eine Vielzahl von Optionen:

  • Schriftressourcen und Backports im Android SDK, wenn Sie verwenden appcompat

  • Bibliotheken von Drittanbietern für diejenigen, die sie nicht verwenden appcompat, obwohl nicht alle die Definition der Schriftart in Layoutressourcen unterstützen


4
@ Codevalley: In vielerlei Hinsicht ist die bessere Antwort, sich nicht mit benutzerdefinierten Schriftarten zu beschäftigen. Sie sind in der Regel groß, wodurch Ihre Downloads größer werden und die Anzahl der Personen verringert wird, die Ihre App herunterladen und weiterhin verwenden.
CommonsWare

22
@ CommonsWare: Ich stimme nicht unbedingt zu. Die Schrift ist ein wesentlicher Bestandteil des UI-Stylings, wie Sie es mit Hintergrundbildern usw. tun. Und die Größe ist nicht immer immer groß. Zum Beispiel ist die Schriftart in meinem Fall nur 19,6 KB :)
Codevalley

2
@Amit: An diesem Problem hat sich nichts geändert. Es gibt viele Codefragmente, die das Anwenden einer Schriftart auf Ihre Benutzeroberfläche in Java vereinfachen, aber es gibt keine Möglichkeit, dies über XML zu tun.
CommonsWare

1
@Amit: "Aber heißt das, dass ich meine eigenen .ttf- oder .otf-Dateien für benutzerdefinierte Schriftarten erstellen muss?" - ähm, nein. Sie können vorhandene TTF / OTF-Schriftarten verwenden, obwohl möglicherweise nicht alle funktionieren. Bei dieser Frage geht es darum, wie diese Schriftarten auf eine gesamte App angewendet werden können, was immer noch nicht möglich ist. Darauf habe ich in meinem Kommentar Bezug genommen.
CommonsWare

1
Diese akzeptierte Antwort ist veraltet und es wäre großartig, sie zu aktualisieren oder zu löschen.
Sky Kelsey

109

Ja, es ist möglich.

Sie müssen eine benutzerdefinierte Ansicht erstellen, die die Textansicht erweitert.

In attrs.xmlim valuesOrdner:

<resources>
    <declare-styleable name="MyTextView">
        <attr name="first_name" format="string"/>
        <attr name="last_name" format="string"/>
        <attr name="ttf_name" format="string"/>
    </declare-styleable>
</resources>

In main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:lht="http://schemas.android.com/apk/res/com.lht"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TextView  android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="Hello"/>
    <com.lht.ui.MyTextView  
        android:id="@+id/MyTextView"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="Hello friends"
        lht:ttf_name="ITCBLKAD.TTF"
        />   
</LinearLayout>

In MyTextView.java:

package com.lht.ui;

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

public class MyTextView extends TextView {

    Context context;
    String ttfName;

    String TAG = getClass().getName();

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;

        for (int i = 0; i < attrs.getAttributeCount(); i++) {
            Log.i(TAG, attrs.getAttributeName(i));
            /*
             * Read value of custom attributes
             */

            this.ttfName = attrs.getAttributeValue(
                    "http://schemas.android.com/apk/res/com.lht", "ttf_name");
            Log.i(TAG, "firstText " + firstText);
            // Log.i(TAG, "lastText "+ lastText);

            init();
        }

    }

    private void init() {
        Typeface font = Typeface.createFromAsset(context.getAssets(), ttfName);
        setTypeface(font);
    }

    @Override
    public void setTypeface(Typeface tf) {

        // TODO Auto-generated method stub
        super.setTypeface(tf);
    }

}

4
Dies wird funktionieren, aber nur für TextView. Es sind benutzerdefinierte Unterklassen für jede Widget-Klasse erforderlich, die erbt, von TextViewder dieselbe Funktion gewünscht wird.
CommonsWare

Hallo Manish, Danke für die Lösung. Obwohl ich vor einem Problem stehe, wenn ich das benutze. Ich erhalte immer wieder 'keine Ressourcen-ID für das Attribut ttf_name im Paket com.lht.android gefunden'
Kshitij Aggarwal

17
Dies funktioniert, aber vor dem ICS wird für jede Ansicht, die Sie instanziieren, Speicher für die Schriftarten zugewiesen: code.google.com/p/android/issues/detail?id=9904 Eine Möglichkeit, dies zu beheben, besteht darin, einen global zugänglichen zu erstellen statische Hashmap aller instanziierten Schriftarten: code.google.com/p/android/issues/detail?id=9904#c7
Ken Van Hoeylandt

Warum brauchen wir eine Schleife? Sollte sie nicht mit einem einzigen Aufruf funktionieren?
Guillermo Tobar

1
@ AlaksiejN. für den Fall, dass Sie unterschiedliche Schriftarten auf unterschiedliche TextViews einstellen müssen ...
Nick

49

Ich habe dies auf eine "Brute Force" -Methode getan, die keine Änderungen an der Layout-XML oder den Aktivitäten erfordert.

Getestet auf Android Version 2.1 bis 4.4. Führen Sie dies beim Start der App in Ihrer Anwendungsklasse aus:

private void setDefaultFont() {

    try {
        final Typeface bold = Typeface.createFromAsset(getAssets(), DEFAULT_BOLD_FONT_FILENAME);
        final Typeface italic = Typeface.createFromAsset(getAssets(), DEFAULT_ITALIC_FONT_FILENAME);
        final Typeface boldItalic = Typeface.createFromAsset(getAssets(), DEFAULT_BOLD_ITALIC_FONT_FILENAME);
        final Typeface regular = Typeface.createFromAsset(getAssets(),DEFAULT_NORMAL_FONT_FILENAME);

        Field DEFAULT = Typeface.class.getDeclaredField("DEFAULT");
        DEFAULT.setAccessible(true);
        DEFAULT.set(null, regular);

        Field DEFAULT_BOLD = Typeface.class.getDeclaredField("DEFAULT_BOLD");
        DEFAULT_BOLD.setAccessible(true);
        DEFAULT_BOLD.set(null, bold);

        Field sDefaults = Typeface.class.getDeclaredField("sDefaults");
        sDefaults.setAccessible(true);
        sDefaults.set(null, new Typeface[]{
                regular, bold, italic, boldItalic
        });

    } catch (NoSuchFieldException e) {
        logFontError(e);
    } catch (IllegalAccessException e) {
        logFontError(e);
    } catch (Throwable e) {
        //cannot crash app if there is a failure with overriding the default font!
        logFontError(e);
    }
}

Ein vollständigeres Beispiel finden Sie unter http://github.com/perchrh/FontOverrideExample


Dies ist die beste Lösung für mich.
Igor K

2
Standard funktioniert nicht für mich. Wenn ich Monospace verwende und dann code<style name = "AppTheme" parent = "AppBaseTheme"> <item name = "android: typeface"> Monospace </ item> </ style> setze code, funktioniert es, aber nicht fett. Ich habe diesen Code in einer Klasse hinzugefügt, die Application erweitert. ist das der richtige Ort? @ P-Chan
Christopher Rivera

2
@ChristopherRivera Ja, fügen Sie es der Anwendungsklasse Ihrer App hinzu und stellen Sie sicher, dass es auf onCreate ausgeführt wird. Wenn Sie sich grepcode.com/file/repository.grepcode.com/java/ext/… ansehen, würde ich vorschlagen, dass Sie das zusätzliche Feld für Monospace sowie das in meinem obigen Beispielcode überschreiben!
Per Christian Henden

2
Okay, ich habe mich für das Feld SERIF geändert und es hat funktioniert :)
Abdullah Umer

3
Diese Antwort verweist auf diese Antwort und bietet imho einen saubereren Ansatz.
Adamdport

36

Obwohl ich Manishs Antwort als die schnellste und zielgerichteteste Methode unterstütze, habe ich auch naive Lösungen gesehen, die nur rekursiv durch eine Ansichtshierarchie iterieren und die Schriften aller Elemente nacheinander aktualisieren. Etwas wie das:

public static void applyFonts(final View v, Typeface fontToSet)
{
    try {
        if (v instanceof ViewGroup) {
            ViewGroup vg = (ViewGroup) v;
            for (int i = 0; i < vg.getChildCount(); i++) {
                View child = vg.getChildAt(i);
                applyFonts(child, fontToSet);
            }
        } else if (v instanceof TextView) {
            ((TextView)v).setTypeface(fontToSet);
        }
    } catch (Exception e) {
        e.printStackTrace();
        // ignore
    }
}

Sie müssten diese Funktion in Ihren Ansichten sowohl nach dem Aufblasen des Layouts als auch in den onContentChanged()Methoden Ihrer Aktivität aufrufen .


Ja schon. Zu dieser Zeit war dies die einzige Möglichkeit, dies innerhalb des Projektzeitraums zu tun. Eine praktische Abkürzung, falls erforderlich (:
Pospi

23

Ich konnte dies zentral tun, hier ist das Ergebnis:

Geben Sie hier die Bildbeschreibung ein

Ich habe Folgendes Activityund ich erweitere es, wenn ich benutzerdefinierte Schriftarten benötige:

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater.Factory;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class CustomFontActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    getLayoutInflater().setFactory(new Factory() {

        @Override
        public View onCreateView(String name, Context context,
                AttributeSet attrs) {
            View v = tryInflate(name, context, attrs);
            if (v instanceof TextView) {
                setTypeFace((TextView) v);
            }
            return v;
        }
    });
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

private View tryInflate(String name, Context context, AttributeSet attrs) {
    LayoutInflater li = LayoutInflater.from(context);
    View v = null;
    try {
        v = li.createView(name, null, attrs); 
    } catch (Exception e) {
        try {
            v = li.createView("android.widget." + name, null, attrs);
        } catch (Exception e1) {
        }
    }
    return v;
}

private void setTypeFace(TextView tv) {
    tv.setTypeface(FontUtils.getFonts(this, "MTCORSVA.TTF"));
}
}

Wenn ich jedoch eine Aktivität aus dem Support-Paket verwende, z. B. FragmentActivitydann Activity:

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class CustomFontFragmentActivity extends FragmentActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

// we can't setLayout Factory as its already set by FragmentActivity so we
// use this approach
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    View v = super.onCreateView(name, context, attrs);
    if (v == null) {
        v = tryInflate(name, context, attrs);
        if (v instanceof TextView) {
            setTypeFace((TextView) v);
        }
    }
    return v;
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public View onCreateView(View parent, String name, Context context,
        AttributeSet attrs) {
    View v = super.onCreateView(parent, name, context, attrs);
    if (v == null) {
        v = tryInflate(name, context, attrs);
        if (v instanceof TextView) {
            setTypeFace((TextView) v);
        }
    }
    return v;
}

private View tryInflate(String name, Context context, AttributeSet attrs) {
    LayoutInflater li = LayoutInflater.from(context);
    View v = null;
    try {
        v = li.createView(name, null, attrs);
    } catch (Exception e) {
        try {
            v = li.createView("android.widget." + name, null, attrs);
        } catch (Exception e1) {
        }
    }
    return v;
}

private void setTypeFace(TextView tv) {
    tv.setTypeface(FontUtils.getFonts(this, "MTCORSVA.TTF"));
}
}

Ich habe diesen Code noch nicht mit Fragments getestet , aber hoffentlich funktioniert es.

Mein FontUtilsist einfach, wodurch auch das hier erwähnte Problem vor dem ICS gelöst wird : https://code.google.com/p/android/issues/detail?id=9904 :

import java.util.HashMap;
import java.util.Map;

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

public class FontUtils {

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

public static Typeface getFonts(Context context, String name) { 
    Typeface typeface = TYPEFACE.get(name);
    if (typeface == null) {
        typeface = Typeface.createFromAsset(context.getAssets(), "fonts/"
                + name);
        TYPEFACE.put(name, typeface);
    }
    return typeface;
}
}

2
Dies sollte mehr Stimmen bekommen. Es funktioniert und es hat einen Screenshot zur Demonstration
Ericn

10

Hey, ich brauche auch 2 verschiedene Schriftarten in meiner App für verschiedene Widgeds! Ich benutze diesen Weg:

In meiner Anwendungsklasse erstelle ich eine statische Methode:

public static Typeface getTypeface(Context context, String typeface) {
    if (mFont == null) {
        mFont = Typeface.createFromAsset(context.getAssets(), typeface);
    }
    return mFont;
}

Die String-Schrift repräsentiert die Datei xyz.ttf im Asset-Ordner. (Ich habe eine Konstantenklasse erstellt.) Jetzt können Sie diese überall in Ihrer App verwenden:

mTextView = (TextView) findViewById(R.id.text_view);
mTextView.setTypeface(MyApplication.getTypeface(this, Constants.TYPEFACE_XY));

Das einzige Problem ist, dass Sie dies für jedes Widget benötigen, in dem Sie die Schriftart verwenden möchten! Aber ich denke, das ist der beste Weg.


4

Mit dem Vorschlag von pospi und der Arbeit mit der Eigenschaft 'tag' wie Richard habe ich eine benutzerdefinierte Klasse erstellt, die meine benutzerdefinierten Schriftarten lädt und sie entsprechend ihren Tags auf die Ansichten anwendet.

Anstatt das TypeFace im Attribut android: fontFamily festzulegen, verwenden Sie das android: tag attritube und setzen es auf eine der definierten Aufzählungen.

public class Fonts {
    private AssetManager mngr;

    public Fonts(Context context) {
        mngr = context.getAssets();
    }
    private enum AssetTypefaces {
        RobotoLight,
        RobotoThin,
        RobotoCondensedBold,
        RobotoCondensedLight,
        RobotoCondensedRegular
    }

    private Typeface getTypeface(AssetTypefaces font) {
        Typeface tf = null;
        switch (font) {
            case RobotoLight:
                tf = Typeface.createFromAsset(mngr,"fonts/Roboto-Light.ttf");
                break;
            case RobotoThin:
                tf = Typeface.createFromAsset(mngr,"fonts/Roboto-Thin.ttf");
                break;
            case RobotoCondensedBold:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Bold.ttf");
                break;
            case RobotoCondensedLight:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Light.ttf");
                break;
            case RobotoCondensedRegular:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Regular.ttf");
                break;
            default:
                tf = Typeface.DEFAULT;
                break;
        }
        return tf;
    }
    public void setupLayoutTypefaces(View v) {
        try {
            if (v instanceof ViewGroup) {
                ViewGroup vg = (ViewGroup) v;
                for (int i = 0; i < vg.getChildCount(); i++) {
                    View child = vg.getChildAt(i);
                    setupLayoutTypefaces(child);
                }
            } else if (v instanceof TextView) {
                if (v.getTag().toString().equals(AssetTypefaces.RobotoLight.toString())){
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoLight));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedRegular.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedRegular));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedBold.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedBold));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedLight.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedLight));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoThin.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoThin));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            // ignore
        }
    }
}

In Ihrer Aktivität oder Ihrem Fragment rufen Sie einfach an

Fonts fonts = new Fonts(getActivity());
fonts.setupLayoutTypefaces(mainLayout);

4

Ich habe im Blog von Lisa Wray eine schöne Lösung gefunden . Mit der neuen Datenbindung ist es möglich, die Schriftart in Ihren XML-Dateien festzulegen.

@BindingAdapter({"bind:font"})
public static void setFont(TextView textView, String fontName){
    textView.setTypeface(Typeface.createFromAsset(textView.getContext().getAssets(), "fonts/" + fontName));
}

In XML:

<TextView
app:font="@{`Source-Sans-Pro-Regular.ttf`}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

Können Sie ein Beispiel für die Datenbindung vorschlagen? Das wäre sehr dankbar.
Sri Krishna

3

Ich denke, es kann einen handlicheren Weg geben, dies zu tun. Die folgende Klasse legt eine benutzerdefinierte Schriftart für alle Komponenten Ihrer Anwendung fest (mit einer Einstellung pro Klasse).

/**
 * Base Activity of our app hierarchy.
 * @author SNI
 */
public class BaseActivity extends Activity {

    private static final String FONT_LOG_CAT_TAG = "FONT";
    private static final boolean ENABLE_FONT_LOGGING = false;

    private Typeface helloTypeface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        helloTypeface = Typeface.createFromAsset(getAssets(), "fonts/<your type face in assets/fonts folder>.ttf");
    }

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        View view = super.onCreateView(name, context, attrs);
        return setCustomTypeFaceIfNeeded(name, attrs, view);
    }

    @Override
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
        View view = super.onCreateView(parent, name, context, attrs);
        return setCustomTypeFaceIfNeeded(name, attrs, view);
    }

    protected View setCustomTypeFaceIfNeeded(String name, AttributeSet attrs, View view) {
        View result = null;
        if ("TextView".equals(name)) {
            result = new TextView(this, attrs);
            ((TextView) result).setTypeface(helloTypeface);
        }

        if ("EditText".equals(name)) {
            result = new EditText(this, attrs);
            ((EditText) result).setTypeface(helloTypeface);
        }

        if ("Button".equals(name)) {
            result = new Button(this, attrs);
            ((Button) result).setTypeface(helloTypeface);
        }

        if (result == null) {
            return view;
        } else {
            if (ENABLE_FONT_LOGGING) {
                Log.v(FONT_LOG_CAT_TAG, "A type face was set on " + result.getId());
            }
            return result;
        }
    }

}

2

Die Standardimplementierungen von LayoutInflater unterstützen die Angabe der Schriftart aus XML nicht. Ich habe es jedoch in XML gesehen, indem ich eine benutzerdefinierte Factory für den LayoutInflater bereitgestellt habe, die solche Attribute aus dem XML-Tag analysiert.

Die Grundstruktur würde dies mögen.

public class TypefaceInflaterFactory implements LayoutInflater.Factory {

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        // CUSTOM CODE TO CREATE VIEW WITH TYPEFACE HERE
        // RETURNING NULL HERE WILL TELL THE INFLATER TO USE THE
        // DEFAULT MECHANISMS FOR INFLATING THE VIEW FROM THE XML
    }

}

public class BaseActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater.from(this).setFactory(new TypefaceInflaterFactory());
    }
}

Dieser Artikel enthält eine ausführlichere Erläuterung dieser Mechanismen und wie der Autor versucht, auf diese Weise die Unterstützung des XML-Layouts für Schriftarten bereitzustellen. Den Code für die Implementierung des Autors finden Sie hier .


1

Festlegen einer benutzerdefinierten Schriftart auf einen regulären ProgressDialog / AlertDialog:

font=Typeface.createFromAsset(getAssets(),"DroidSans.ttf");

ProgressDialog dialog = ProgressDialog.show(this, "titleText", "messageText", true);
((TextView)dialog.findViewById(Resources.getSystem().getIdentifier("message", "id", "android"))).setTypeface(font);
((TextView)dialog.findViewById(Resources.getSystem().getIdentifier("alertTitle", "id", "android"))).setTypeface(font);

1

Ja, es ist möglich, indem die Standardschrift überschrieben wird. Ich folgte dieser Lösung und sie funktionierte mit einer einzigen Änderung wie ein Zauber für alle TextViews und ActionBar-Texte.

public class MyApp extends Application {

  @Override
  public void onCreate() {
    TypefaceUtil.overrideFont(getApplicationContext(), "SERIF", "fonts/Roboto-Regular.ttf"); // font from assets: "assets/fonts/Roboto-Regular.ttf
  }
}

styles.xml

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/pantone</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowTranslucentStatus" tools:targetApi="kitkat">true</item>
    <item name="android:windowDisablePreview">true</item>
    <item name="android:typeface">serif</item>
</style>

Anstelle von theme.xml, wie im obigen Link erwähnt, habe ich die Standardschriftart erwähnt, die in meiner styles.xml in meinem Standard-App-Theme-Tag überschrieben werden soll. Die Standardschriften, die überschrieben werden können, sind Serif, Sans, Monospace und Normal.

TypefaceUtil.java

public class TypefaceUtil {

    /**
     * Using reflection to override default typeface
     * NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE OVERRIDDEN
     * @param context to work with assets
     * @param defaultFontNameToOverride for example "monospace"
     * @param customFontFileNameInAssets file name of the font from assets
     */
    public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
        try {
            final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);

            final Field defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
            defaultFontTypefaceField.setAccessible(true);
            defaultFontTypefaceField.set(null, customFontTypeface);
        } catch (Exception e) {
            Log.e("Can not set custom font " + customFontFileNameInAssets + " instead of " + defaultFontNameToOverride);
        }
    }
}

Anfangs wusste ich nicht, dass die zu überschreibenden Schriftarten fest sind und definierte Werte enthalten, aber schließlich half es mir zu verstehen, wie Android mit Schriftarten und Schriftarten und ihren Standardwerten umgeht, was ein anderer Punkt ist.


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

2
Leider funktioniert dies nicht mehr: java.lang.IllegalAccessException: Feld wird bei java.lang.reflect.Field.setField (native Methode) bei java.lang.reflect.Field.set (Field.java: 'final' markiert. 556)
BoD

0

Ich mag Pospis Vorschlag. Warum nicht alles daran setzen? Verwenden Sie die Eigenschaft 'tag' einer Ansicht (die Sie in XML angeben können - 'android: tag'), um zusätzliche Stile anzugeben, die Sie in XML nicht ausführen können. Ich mag JSON, daher würde ich eine JSON-Zeichenfolge verwenden, um einen Schlüssel- / Wertesatz anzugeben. Diese Klasse erledigt die Arbeit - rufen Style.setContentView(this, [resource id])Sie einfach Ihre Aktivität an.

public class Style {

  /**
   * Style a single view.
   */
  public static void apply(View v) {
    if (v.getTag() != null) {
      try {
        JSONObject json = new JSONObject((String)v.getTag());
        if (json.has("typeface") && v instanceof TextView) {
          ((TextView)v).setTypeface(Typeface.createFromAsset(v.getContext().getAssets(),
                                                             json.getString("typeface")));
        }
      }
      catch (JSONException e) {
        // Some views have a tag without it being explicitly set!
      }
    }
  }

  /**
   * Style the passed view hierarchy.
   */
  public static View applyTree(View v) {
    apply(v);
    if (v instanceof ViewGroup) {
      ViewGroup g = (ViewGroup)v;
      for (int i = 0; i < g.getChildCount(); i++) {
        applyTree(g.getChildAt(i));
      }
    }
    return v;
  }

  /**
   * Inflate, style, and set the content view for the passed activity.
   */
  public static void setContentView(Activity activity, int resource) {
    activity.setContentView(applyTree(activity.getLayoutInflater().inflate(resource, null)));
  }
}

Natürlich möchten Sie mehr als nur die Schrift verarbeiten, damit sich die Verwendung von JSON lohnt.

Ein Vorteil der Eigenschaft 'tag' besteht darin, dass Sie sie auf einen Basisstil festlegen können, den Sie als Thema verwenden, und sie somit automatisch auf alle Ihre Ansichten anwenden können. BEARBEITEN: Dies führt zu einem Absturz während des Aufblasens unter Android 4.0.3. Sie können einen Stil weiterhin verwenden und ihn einzeln auf Textansichten anwenden.

Eine Sache, die Sie im Code sehen werden - einige Ansichten haben ein Tag, ohne dass eines explizit festgelegt wurde - seltsamerweise ist es die Zeichenfolge 'Αποκοπή' - die laut Google Translate auf Griechisch 'geschnitten' ist! Was zum Teufel...?


0

Die Antwort von @ majinboo wurde hinsichtlich Leistung und Speicherverwaltung überarbeitet. Für mehr als eine Schriftart, die eine verwandte Aktivität benötigt, kann diese Schriftartklasse verwendet werden, indem der Konstruktor selbst als Parameter angegeben wird.

@Override
public void onCreate(Bundle savedInstanceState)
{
    Font font = new Font(this);
}

Die Klasse der überarbeiteten Schriftarten lautet wie folgt:

public class Fonts
{
    private HashMap<AssetTypefaces, Typeface> hashMapFonts;

    private enum AssetTypefaces
    {
        RobotoLight,
        RobotoThin,
        RobotoCondensedBold,
        RobotoCondensedLight,
        RobotoCondensedRegular
    }

    public Fonts(Context context)
    {
        AssetManager mngr = context.getAssets();

        hashMapFonts = new HashMap<AssetTypefaces, Typeface>();
        hashMapFonts.put(AssetTypefaces.RobotoLight, Typeface.createFromAsset(mngr, "fonts/Roboto-Light.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoThin, Typeface.createFromAsset(mngr, "fonts/Roboto-Thin.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedBold, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Bold.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedLight, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Light.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedRegular, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Regular.ttf"));
    }

    private Typeface getTypeface(String fontName)
    {
        try
        {
            AssetTypefaces typeface = AssetTypefaces.valueOf(fontName);
            return hashMapFonts.get(typeface);
        }
        catch (IllegalArgumentException e)
        {
            // e.printStackTrace();
            return Typeface.DEFAULT;
        }
    }

    public void setupLayoutTypefaces(View v)
    {
        try
        {
            if (v instanceof ViewGroup)
            {
                ViewGroup vg = (ViewGroup) v;
                for (int i = 0; i < vg.getChildCount(); i++)
                {
                    View child = vg.getChildAt(i);
                    setupLayoutTypefaces(child);
                }
            }
            else if (v instanceof TextView)
            {
                ((TextView) v).setTypeface(getTypeface(v.getTag().toString()));
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            // ignore
        }
    }
}

0

Arbeiten für Xamarin.Android:

Klasse:

public class FontsOverride
{
    public static void SetDefaultFont(Context context, string staticTypefaceFieldName, string fontAssetName)
    {
        Typeface regular = Typeface.CreateFromAsset(context.Assets, fontAssetName);
        ReplaceFont(staticTypefaceFieldName, regular);
    }

    protected static void ReplaceFont(string staticTypefaceFieldName, Typeface newTypeface)
    {
        try
        {
            Field staticField = ((Java.Lang.Object)(newTypeface)).Class.GetDeclaredField(staticTypefaceFieldName);
            staticField.Accessible = true;
            staticField.Set(null, newTypeface);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

Anwendungsimplementierung:

namespace SomeAndroidApplication
{
    [Application]
    public class App : Application
    {
        public App()
        {

        }

        public App(IntPtr handle, JniHandleOwnership transfer)
            : base(handle, transfer)
        {

        }

        public override void OnCreate()
        {
            base.OnCreate();

            FontsOverride.SetDefaultFont(this, "MONOSPACE", "fonts/Roboto-Light.ttf");
        }
    }
}

Stil:

<style name="Theme.Storehouse" parent="Theme.Sherlock">
    <item name="android:typeface">monospace</item>
</style>

0

Es sieht so aus, als ob die Verwendung von benutzerdefinierten Schriftarten mit Android O vereinfacht wurde. Sie können grundsätzlich XML verwenden, um dies zu erreichen. Ich habe einen Link zur offiziellen Dokumentation von Android als Referenz angehängt, und hoffentlich hilft dies Menschen, die diese Lösung noch benötigen. Arbeiten mit benutzerdefinierten Schriftarten in Android


0

Es kann nützlich sein zu wissen, dass Sie ab Android 8.0 (API-Level 26) können eine benutzerdefinierte Schriftart in XML verwenden können .

Einfach ausgedrückt, können Sie dies folgendermaßen tun.

  1. Legen Sie die Schriftart in den Ordner res/font .

  2. Verwenden Sie es entweder im Attribut eines Widgets

<Button android:fontFamily="@font/myfont"/>

oder setzen Sie es in res/values/styles.xml

<style name="MyButton" parent="android:Widget.Button">
    <item name="android:fontFamily">@font/myfont</item>
</style>

und benutze es als Stil

<Button style="@style/MyButton"/>

0

Verwenden Sie das Attribut "fontPath" direkt in der XML-Datei.

zur Verwendung in style.xml

<item name = "fontPath"> fonts / ProximaNovaSemibold.ttf </ item>

zur Verwendung in direkten Layoutdateien

fontPath = "fonts / ProximaNovaBold.ttf"

(Hinweis: Das Präfix app / android muss nicht im Präfix verwendet werden.)


-6

Absolut möglich. Viele Möglichkeiten, es zu tun. Am schnellsten erstellen Sie eine Bedingung mit der try-catch-Methode. Probieren Sie Ihre bestimmte Schriftstilbedingung aus, fangen Sie den Fehler ab und definieren Sie den anderen Schriftstil.


7
Können Sie eine Demo bereitstellen, um zu beweisen, dass Sie antworten?
Mark
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.