Utiliser une police de caractères personnalisée dans Android

Je veux utiliser une police personnalisée pour mon application Android que je crée.
Je peux changer individuellement la police de chaque object à partir de Code, mais j’en ai des centaines.

Alors,

  • Y at-il un moyen de le faire à partir du XML? [Définition d’une police de caractères personnalisée]
  • Y a-t-il un moyen de le faire à partir du code en un seul endroit, pour dire que l’application entière et tous les composants doivent utiliser la police de caractères personnalisée au lieu de la police par défaut?

Y at-il un moyen de le faire à partir du XML?

Non désolé. Vous ne pouvez spécifier que les fonts de caractères intégrées via XML.

Y a-t-il un moyen de le faire à partir du code en un seul endroit, pour dire que l’application entière et tous les composants doivent utiliser la police de caractères personnalisée au lieu de la police par défaut?

Pas que je sache.

Il existe une variété d’options pour ces jours:

  • Ressources de fonts et backports dans le SDK Android, si vous utilisez appcompat

  • Bibliothèques tierces pour ceux qui n’utilisent pas appcompat , mais tous ne prendront pas en charge la définition de la police dans les ressources de présentation

Oui c’est possible.

Vous devez créer une vue personnalisée qui étend la vue du texte.

Dans attrs.xml dans le dossier de values :

        

Dans main.xml :

     

Dans MyTextView.java :

 package com.lht.ui; import android.content.Context; import android.graphics.Typeface; import android.util.AtsortingbuteSet; import android.util.Log; import android.widget.TextView; public class MyTextView extends TextView { Context context; Ssortingng ttfName; Ssortingng TAG = getClass().getName(); public MyTextView(Context context, AtsortingbuteSet 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); } } 

Je l’ai fait d’une manière plus “brute” qui ne nécessite pas de modifications au format xml ou aux activités.

Testé sur les versions Android 2.1 à 4.4. Exécutez ceci au démarrage de l’application, dans votre classe Application:

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

Pour un exemple plus complet, voir http://github.com/perchrh/FontOverrideExample

Bien que je vote la réponse de Manish comme la méthode la plus rapide et la plus ciblée, j’ai également vu des solutions naïves qui effectuent une itération récursive dans une hiérarchie de vues et mettent à jour toutes les fonts de caractères de chaque élément. Quelque chose comme ça:

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

Vous devez appeler cette fonction sur vos vues après avoir gonflé la mise en forme et dans les méthodes onContentChanged() votre activité.

J’ai pu le faire de manière centralisée, voici le résultat:

entrer la description de l'image ici

J’ai l’ Activity suivante et je l’étend si j’ai besoin de fonts personnalisées:

 import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.util.AtsortingbuteSet; 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(Ssortingng name, Context context, AtsortingbuteSet 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(Ssortingng name, Context context, AtsortingbuteSet 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")); } } 

Mais si j’utilise une activité du package de support, par exemple FragmentActivity j’utilise cette 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.AtsortingbuteSet; 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(Ssortingng name, Context context, AtsortingbuteSet 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, Ssortingng name, Context context, AtsortingbuteSet 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(Ssortingng name, Context context, AtsortingbuteSet 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")); } } 

Je n’ai pas encore testé ce code avec Fragment , mais j’espère que cela fonctionnera.

Mon FontUtils est simple, ce qui résout également le problème pré-ICS mentionné ici 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 TYPEFACE = new HashMap(); public static Typeface getFonts(Context context, Ssortingng name) { Typeface typeface = TYPEFACE.get(name); if (typeface == null) { typeface = Typeface.createFromAsset(context.getAssets(), "fonts/" + name); TYPEFACE.put(name, typeface); } return typeface; } } 

Hey j’ai aussi besoin de 2 fonts différentes dans mon application pour différents verges! J’utilise cette façon:

Dans ma classe d’application, je crée une méthode statique:

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

La police de caractères Ssortingng représente le fichier xyz.ttf dans le dossier des ressources. (J’ai créé une classe de constantes) Maintenant, vous pouvez l’utiliser partout dans votre application:

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

Le seul problème est que vous en avez besoin pour chaque widget où vous souhaitez utiliser la police! Mais je pense que c’est la meilleure façon.

En utilisant la suggestion de pospi et en travaillant avec la propriété ‘tag’ comme Richard , j’ai créé une classe personnalisée qui charge mes fonts personnalisées et les applique aux vues en fonction de leurs balises.

Donc, fondamentalement, au lieu de définir le TypeFace dans l’atsortingbut android: fontFamily, vous utilisez l’android: marquez atsortingtube et réglez-le sur l’un des énumérations définies.

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

Dans votre activité ou fragment, il vous suffit d'appeler

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

Je pense qu’il peut y avoir un moyen plus pratique de le faire. La classe suivante définira un type de visage personnalisé pour tous les composants de votre application (avec un paramètre par classe).

 /** * Base Activity of our app hierarchy. * @author SNI */ public class BaseActivity extends Activity { private static final Ssortingng 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/.ttf"); } @Override public View onCreateView(Ssortingng name, Context context, AtsortingbuteSet attrs) { View view = super.onCreateView(name, context, attrs); return setCustomTypeFaceIfNeeded(name, attrs, view); } @Override public View onCreateView(View parent, Ssortingng name, Context context, AtsortingbuteSet attrs) { View view = super.onCreateView(parent, name, context, attrs); return setCustomTypeFaceIfNeeded(name, attrs, view); } protected View setCustomTypeFaceIfNeeded(Ssortingng name, AtsortingbuteSet 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; } } } 

J’ai trouvé une solution intéressante sur le blog de Lisa Wray . Avec la nouvelle liaison de données, il est possible de définir la police dans vos fichiers XML.

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

En XML:

  

Les implémentations par défaut de LayoutInflater ne prennent pas en charge la spécification de la police de caractères à partir de xml. Je l’ai cependant vu faire en xml en fournissant une fabrique personnalisée pour le LayoutInflater qui parsingra de tels atsortingbuts à partir de la balise XML.

La structure de base aimerait cela.

 public class TypefaceInflaterFactory implements LayoutInflater.Factory { @Override public View onCreateView(Ssortingng name, Context context, AtsortingbuteSet 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()); } } 

Cet article fournit une explication plus détaillée de ces mécanismes et explique comment l’auteur tente de fournir un support de présentation XML pour les caractères de cette manière. Le code pour la mise en œuvre de l’auteur peut être trouvé ici .

Définir une police personnalisée sur 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); 

Oui, c’est possible en remplaçant la police par défaut. J’ai suivi cette solution et cela a fonctionné comme un charme pour tous les textes TextViews et ActionBar également avec un seul changement.

 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

   

Au lieu de themes.xml comme mentionné dans le lien ci-dessus, j’ai mentionné la police par défaut à remplacer dans mes styles.xml dans mon tag de thème d’application par défaut. Les fonts par défaut pouvant être écrasées sont serif, sans, monospace et 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, Ssortingng defaultFontNameToOverride, Ssortingng 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); } } } 

Au départ, je ne savais pas que les fonts à remplacer étaient fixes et définissaient des valeurs définies, mais finalement, cela m’a aidé à comprendre comment Android gère les fonts et les caractères et leurs valeurs par défaut, ce qui est un sharepoint vue différent.

Je ne sais pas si cela change toute l’application, mais j’ai réussi à changer certains composants qui ne pourraient pas être modifiés autrement en procédant comme suit:

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

J’aime la suggestion de pospi. Pourquoi ne pas utiliser la propriété ‘tag’ d’une vue (que vous pouvez spécifier dans XML – ‘android: tag’) pour spécifier tout style supplémentaire que vous ne pouvez pas faire en XML. J’aime JSON donc j’utiliserais une chaîne JSON pour spécifier un ensemble clé / valeur. Cette classe fait le travail – il suffit d’appeler Style.setContentView(this, [resource id]) dans votre activité.

 public class Style { /** * Style a single view. */ public static void apply(View v) { if (v.getTag() != null) { try { JSONObject json = new JSONObject((Ssortingng)v.getTag()); if (json.has("typeface") && v instanceof TextView) { ((TextView)v).setTypeface(Typeface.createFromAsset(v.getContext().getAssets(), json.getSsortingng("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))); } } 

De toute évidence, vous voudriez gérer plus que la police pour utiliser JSON.

Un des avantages de la propriété 'tag' est que vous pouvez la définir sur un style de base que vous utilisez comme thème et l’appliquer automatiquement à toutes vos vues. EDIT: Cela provoque un crash lors de l'inflation sur Android 4.0.3. Vous pouvez toujours utiliser un style et l'appliquer aux vues de texte individuellement.

Une chose que vous verrez dans le code - certaines vues ont une balise sans que celle-ci ne soit explicitement définie - bizarrement, c'est la chaîne "οποκοπή" - qui est "coupée" en grec, selon google translate! Que se passe-t-il...?

La réponse de @ majinboo est révisée pour la gestion des performances et de la mémoire. Plus d’une police a besoin d’activité liée peut utiliser cette classe de police en donnant le constructeur lui-même en tant que paramètre.

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

La classe de fonts révisée est la suivante:

 public class Fonts { private HashMap hashMapFonts; private enum AssetTypefaces { RobotoLight, RobotoThin, RobotoCondensedBold, RobotoCondensedLight, RobotoCondensedRegular } public Fonts(Context context) { AssetManager mngr = context.getAssets(); hashMapFonts = new HashMap(); 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(Ssortingng 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 } } } 

Travailler pour Xamarin.Android:

Classe:

 public class FontsOverride { public static void SetDefaultFont(Context context, ssortingng staticTypefaceFieldName, ssortingng fontAssetName) { Typeface regular = Typeface.CreateFromAsset(context.Assets, fontAssetName); ReplaceFont(staticTypefaceFieldName, regular); } protected static void ReplaceFont(ssortingng 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); } } } 

Mise en œuvre de l’application:

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

Style:

  

Il semble que l’utilisation de fonts personnalisées ait été simplifiée avec Android O, vous pouvez en gros utiliser XML pour y parvenir. J’ai attaché un lien vers la documentation officielle d’Android pour référence, et j’espère que cela aidera les personnes qui ont encore besoin de cette solution. Travailler avec des fonts personnalisées dans Android

La nouvelle bibliothèque de support 26 vous permet maintenant d’utiliser des fonts en XML.

Voici comment procéder Polices en XML

Absolument possible. De nombreuses façons de le faire. Le moyen le plus rapide de créer une condition avec la méthode try-catch .. essayez votre condition de police spécifique, détectez l’erreur et définissez l’autre style de police.