Utilisation d'une police personnalisée sous Android


111

Je souhaite utiliser une police personnalisée pour mon application Android que je crée.
Je peux modifier individuellement la police de caractères de chaque objet à partir de Code, mais j'en ai des centaines.

Alors,

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

stackoverflow.com/questions/5541058/… Regardez ce post J'ai posté le code complet ici concernant ce problème
Manish Singla

Vous pouvez utiliser des variables statiques sur votre activité principale pour contenir des références aux polices incorporées. Cela ferait en sorte qu'il y ait un ensemble persistant de polices qui ne seront pas récupérées par GC.
Jacksonkr

Méthode d'usine. Ou une méthode qui prend votre avis et définit tous les paramètres de police et de police.
mtmurdock

La nouvelle bibliothèque de support 26 vous permet désormais d'utiliser des polices en XML. Voici comment faire Polices en XML
Vinicius Silva

Réponses:


80

Existe-t-il un moyen de le faire à partir du XML?

Non désolé. Vous ne pouvez spécifier les polices intégrées que via XML.

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

Pas que je sache.

Il existe aujourd'hui une variété d'options pour ces derniers:

  • Ressources de polices et rétroportages dans le SDK Android, si vous utilisez appcompat

  • Bibliothèques tierces pour ceux qui n'utilisent pas appcompat, bien que toutes ne prennent pas en charge la définition de la police dans les ressources de mise en page


4
@Codevalley: Eh bien, à bien des égards, la meilleure réponse est de ne pas s'embarrasser de polices personnalisées. Ils ont tendance à être volumineux, ce qui augmente vos téléchargements et réduit le nombre de personnes qui téléchargeront et continueront à utiliser votre application.
CommonsWare

22
@CommonsWare: Je ne suis pas nécessairement d'accord. La police fait partie intégrante du style de l'interface utilisateur, comme vous le faites avec les images d'arrière-plan, etc. Et la taille n'est pas toujours nécessairement grande. Par exemple, la police dans mon cas ne fait que 19,6 Ko :)
Codevalley

2
@Amit: Il n'y a eu aucun changement sur ce problème. Il existe de nombreux extraits de code pour simplifier l'application d'une police à votre interface utilisateur en Java, mais il n'y a aucun moyen de le faire à partir de XML.
CommonsWare

1
@Amit: "Mais cela signifie-t-il que je devrai créer mes propres fichiers .ttf ou .otf pour les polices personnalisées?" -- um non. Vous pouvez utiliser les polices TTF / OTF existantes, même si elles ne fonctionnent pas toutes. Le problème sur cette question est de savoir comment appliquer ces polices à l'ensemble d'une application, ce qui n'est toujours pas possible, et c'est ce à quoi je faisais référence dans mon commentaire.
CommonsWare

1
Cette réponse acceptée est obsolète et il serait bon de la mettre à jour ou de la supprimer.
Sky Kelsey

109

Oui c'est possible.

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

Dans attrs.xmldans le valuesdossier:

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

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

Dans 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
Cela fonctionnera, mais seulement pour TextView. Cela nécessitera des sous-classes personnalisées pour chaque classe de widget qui hérite de l' TextViewendroit où la même capacité est souhaitée.
CommonsWare

Salut Manish, Merci pour la solution. Bien que je fasse face à un problème d'utilisation de cela. Je continue à obtenir `` aucun identifiant de ressource trouvé pour l'attribut ttf_name dans le package com.lht.android ''
Kshitij Aggarwal

17
Cela fonctionnera, mais avant ICS, il allouera de la mémoire pour les polices pour chaque vue que vous instanciez: code.google.com/p/android/issues/detail?id=9904 Une façon de résoudre ce problème consiste à créer un fichier accessible à tous. hashmap statique de toutes les polices instanciées: code.google.com/p/android/issues/detail?id=9904#c7
Ken Van Hoeylandt

Pourquoi avons-nous besoin d'une boucle ?, Ne devrait-elle pas fonctionner avec un seul appel?
Guillermo Tobar

1
@AlaksiejN. au cas où vous auriez besoin de définir différentes polices de caractères pour différents TextViews ...
Nick

49

Je l'ai fait d'une manière plus "brute force" qui ne nécessite pas de modifications du format xml ou des activités.

Testé sur la version 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


C'est la meilleure solution pour moi.
Igor K

2
par défaut ne fonctionne pas pour moi. si j'utilise monospace puis que je règle code<style name = "AppTheme" parent = "AppBaseTheme"> <item name = "android: typeface"> monospace </item> </style> codecela fonctionne mais pas pour le gras. j'ai ajouté ce code dans une classe qui étend l'application. est-ce le bon endroit? @ P-chan
Christopher Rivera

2
@ChristopherRivera Oui, ajoutez-le à la classe Application de votre application, assurez-vous qu'il s'exécute sur onCreate. En jetant un œil à grepcode.com/file/repository.grepcode.com/java/ext/ ... Je vous suggère de remplacer le champ supplémentaire pour monospace ainsi que celui de mon exemple de code ci-dessus!
Par Christian Henden

2
D'accord, j'ai changé pour le champ SERIF et ça a marché :)
Abdullah Umer

3
Cette réponse fait référence à cette réponse et fournit une approche plus propre à mon humble avis.
adamdport

36

Bien que j'évalue 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 ne font qu'itérer récursivement dans une hiérarchie de vues et mettre à jour les polices de caractères de tous les éléments à leur tour. 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 devrez appeler cette fonction sur vos vues à la fois après avoir gonflé la mise en page et dans les onContentChanged()méthodes de votre activité .


Plutôt. À l'époque, c'était la seule façon de le faire dans les délais du projet. Un raccourci pratique si nécessaire (:
pospi

23

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

entrez la description de l'image ici

J'ai suivi Activityet j'en étend si j'ai besoin de polices personnalisées:

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

Mais si j'utilise une activité du support package, par exemple, FragmentActivityj'utilise ceci 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"));
}
}

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

My FontUtilsest 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<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
Cela devrait obtenir plus de votes. Cela fonctionne et il a une capture d'écran pour la démonstration
ericn

10

Hé, j'ai également besoin de 2 polices différentes dans mon application pour différents widgeds! J'utilise de cette façon:

Dans ma classe Application, je crée une méthode statique:

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

La police String représente le xyz.ttf dans le dossier des ressources. (J'ai créé une classe de constantes) Vous pouvez maintenant 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 le meilleur moyen.


4

Utiliser la suggestion de pospi et travailler avec la propriété 'tag' comme Richard fait, j'ai créé une classe personnalisée qui charge mes polices personnalisées et les applique aux vues en fonction de leurs balises.

Donc, fondamentalement, au lieu de définir TypeFace dans l'attribut android: fontFamily, vous utilisez android: tag attritube et définissez-le sur l'une 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, vous venez d'appeler

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

4

J'ai trouvé une belle solution 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, String fontName){
    textView.setTypeface(Typeface.createFromAsset(textView.getContext().getAssets(), "fonts/" + fontName));
}

En XML:

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

Pouvez-vous suggérer un exemple utilisant la liaison de données? Ce serait très apprécié.
Sri Krishna

3

Je pense qu'il peut y avoir un moyen plus pratique de le faire. La classe suivante définira un visage de type personnalisé pour tous vos 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 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

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 usine personnalisée pour le LayoutInflater qui analysera ces attributs à partir de la balise xml.

La structure de base aimerait cela.

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

Cet article fournit une explication plus approfondie de ces mécanismes et de la manière dont l'auteur tente de fournir une prise en charge de la mise en page XML pour les polices de cette manière. Le code de l'implémentation de l'auteur peut être trouvé ici .


1

Définition d'une police personnalisée sur un ProgressDialog / AlertDialog normal:

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

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

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

Au lieu de themes.xml comme mentionné dans le lien ci-dessus, j'ai mentionné la police par défaut à remplacer dans mon styles.xml dans ma balise de thème d'application par défaut. Les polices par défaut qui peuvent ê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, 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);
        }
    }
}

Au départ, je ne savais pas que les polices à écraser étaient fixes et constituaient un ensemble de valeurs définies, mais cela m'a finalement aidé à comprendre comment Android traite les polices et les polices et leurs valeurs par défaut, ce qui est bien sûr un point différent.


0

Je ne sais pas si cela change l'ensemble de l'application, mais j'ai réussi à changer certains composants qui ne pourraient autrement pas être modifiés en faisant ceci:

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
Malheureusement, cela ne fonctionne plus: java.lang.IllegalAccessException: le champ est marqué 'final' à java.lang.reflect.Field.setField (méthode native) à java.lang.reflect.Field.set (Field.java: 556)
BoD

0

J'aime la suggestion de pospi. Pourquoi ne pas utiliser à fond la propriété 'tag' d'une vue (que vous pouvez spécifier en 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 - appelez simplement Style.setContentView(this, [resource id])votre activité.

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

De toute évidence, vous voudrez gérer plus que la simple police de caractères pour rendre l'utilisation de JSON intéressante.

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

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


0

La réponse de @ majinboo est révisée pour les performances et la gestion de la mémoire. Toute activité associée à plus d'une police a besoin de cette classe Font en donnant le constructeur lui-même comme paramètre.

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

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

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

Travailler pour Xamarin.Android:

Classe:

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

Implémentation 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:

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

0

Il semble que l'utilisation de polices personnalisées a été facilitée avec Android O, vous pouvez essentiellement utiliser xml pour y parvenir. J'ai joint 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 polices personnalisées sous Android


0

Il peut être utile de savoir qu'à partir d'Android 8.0 (niveau d'API 26), vous pouvez utiliser une police personnalisée en XML .

En termes simples, vous pouvez le faire de la manière suivante.

  1. Mettez la police dans le dossier res/font.

  2. Soit l'utiliser dans l'attribut d'un widget

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

ou mettez-le dans res/values/styles.xml

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

et utilisez-le comme style

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

0

Utilisez l'attribut "fontPath" directement dans le fichier xml.

à utiliser dans style.xml

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

à utiliser dans un fichier de mise en page directe

fontPath = "fonts / ProximaNovaBold.ttf"

(Remarque: pas besoin d'utiliser l'attribut app / android dans le préfixe)


-6

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


7
pouvez-vous fournir une démo pour prouver votre réponse?
Mark
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.