web-dev-qa-db-fra.com

Polices personnalisées et dispositions XML (Android)

J'essaie de définir une disposition d'interface graphique à l'aide de fichiers XML dans Android. Autant que je sache, il n’existe aucun moyen de spécifier que vos widgets doivent utiliser une police personnalisée (par exemple, une police que vous avez placée dans assets/font /) dans des fichiers XML et que vous ne pouvez utiliser que les polices système installées.

Je sais que, dans le code Java, je pouvais modifier manuellement la police de chaque widget à l'aide d'identifiants uniques. Alternativement, je pourrais parcourir tous les widgets en Java pour effectuer ce changement, mais cela serait probablement très lent.

Quelles autres options ai-je? Existe-t-il de meilleurs moyens de créer des widgets à l'apparence personnalisée? Je ne veux pas particulièrement avoir à changer manuellement la police pour chaque nouveau widget que j'ajoute.

171
DrDefrost

Vous pouvez étendre TextView pour définir des polices personnalisées à mesure que j’ai appris ici .

TextViewPlus.Java: 

package com.example;

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

public class TextViewPlus extends TextView {
    private static final String TAG = "TextView";

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

    public TextViewPlus(Context context, AttributeSet attrs) {
        super(context, attrs);
        setCustomFont(context, attrs);
    }

    public TextViewPlus(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setCustomFont(context, attrs);
    }

    private void setCustomFont(Context ctx, AttributeSet attrs) {
        TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.TextViewPlus);
        String customFont = a.getString(R.styleable.TextViewPlus_customFont);
        setCustomFont(ctx, customFont);
        a.recycle();
    }

    public boolean setCustomFont(Context ctx, String asset) {
        Typeface tf = null;
        try {
        tf = Typeface.createFromAsset(ctx.getAssets(), asset);  
        } catch (Exception e) {
            Log.e(TAG, "Could not get typeface: "+e.getMessage());
            return false;
        }

        setTypeface(tf);  
        return true;
    }

}

attrs.xml: (en res/valeurs)

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

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:foo="http://schemas.Android.com/apk/res/com.example"
    Android:orientation="vertical" Android:layout_width="fill_parent"
    Android:layout_height="fill_parent">

    <com.example.TextViewPlus
        Android:id="@+id/textViewPlus1"
        Android:layout_height="match_parent"
        Android:layout_width="match_parent"
        Android:text="@string/showingOffTheNewTypeface"
        foo:customFont="saxmono.ttf">
    </com.example.TextViewPlus>
</LinearLayout>

Vous mettriez "saxmono.ttf" dans le dossier assets.

MISE À JOUR 8/1/13

Il y a de sérieux problèmes de mémoire avec cette méthode. Voir le commentaire de chedabob ci-dessous.

218
peter

Je suis 3 ans de retard pour la fête :( Cependant, cela pourrait être utile pour quelqu'un qui pourrait trébucher sur ce post.

J'ai écrit une bibliothèque qui met en cache les polices et vous permet également de spécifier des polices personnalisées directement à partir de XML. Vous pouvez trouver la bibliothèque ici .

Voici à quoi ressemblerait votre mise en page XML lorsque vous l'utiliserez.

<com.mobsandgeeks.ui.TypefaceTextView
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:text="@string/hello_world"
    geekui:customTypeface="fonts/custom_font.ttf" />
35

Cela peut être un peu tard, mais vous devez créer une classe singleton qui renvoie le caractère personnalisé pour éviter les fuites de mémoire.

Classe TypeFace:

public class OpenSans {

private static OpenSans instance;
private static Typeface typeface;

public static OpenSans getInstance(Context context) {
    synchronized (OpenSans.class) {
        if (instance == null) {
            instance = new OpenSans();
            typeface = Typeface.createFromAsset(context.getResources().getAssets(), "open_sans.ttf");
        }
        return instance;
    }
}

public Typeface getTypeFace() {
    return typeface;
}
}

TextView personnalisé:

public class NativelyCustomTextView extends TextView {

    public NativelyCustomTextView(Context context) {
        super(context);
        setTypeface(OpenSans.getInstance(context).getTypeFace());
    }

    public NativelyCustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setTypeface(OpenSans.getInstance(context).getTypeFace());
    }

    public NativelyCustomTextView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        setTypeface(OpenSans.getInstance(context).getTypeFace());
    }

}

Par xml:

<com.yourpackage.views.NativelyCustomTextView
            Android:id="@+id/natively_text_view"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_centerHorizontal="true"
            Android:layout_margin="20dp"
            Android:text="@string/natively"
            Android:textSize="30sp" /> 

Par programme:

TextView programmaticallyTextView = (TextView) 
       findViewById(R.id.programmatically_text_view);

programmaticallyTextView.setTypeface(OpenSans.getInstance(this)
                .getTypeFace());
18
Leonardo Cardoso

Vieille question, mais j'aimerais bien lire cette réponse ici avant de commencer ma propre recherche d'une bonne solution. Calligraphie étend l'attribut Android:fontFamily pour ajouter la prise en charge des polices personnalisées dans votre dossier de ressources, comme suit:

<TextView 
  Android:text="@string/hello_world"
  Android:layout_width="wrap_content"
  Android:layout_height="wrap_content"
  Android:fontFamily="fonts/Roboto-Bold.ttf"/>

La seule chose que vous devez faire pour l'activer est de l'attacher au contexte de l'activité que vous utilisez:

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(new CalligraphyContextWrapper(newBase));
}

Vous pouvez également spécifier votre propre attribut personnalisé pour remplacer Android:fontFamily.

Il fonctionne également dans des thèmes, y compris AppTheme.

13
thoutbeckers

La meilleure façon de le faire À partir de la version d’aperçu d’Android O est la suivante: 
1.) Cliquez avec le bouton droit de la souris sur le dossier res et accédez à Nouveau> Répertoire de ressources Android. Le nouveau
La fenêtre Répertoire de ressources apparaît.
2.) Dans la liste Type de ressource, sélectionnez font, puis cliquez sur OK.
3.) Ajoutez vos fichiers de polices dans le dossier de polices. La structure de dossiers ci-dessous génère R.font.dancing_script, R.font.la_la et R.font.ba_ba.
4.) Double-cliquez sur un fichier de police pour prévisualiser les polices du fichier dans l'éditeur.

Ensuite, nous devons créer une famille de polices

1.) Cliquez avec le bouton droit sur le dossier de polices et allez à Nouveau> Fichier de ressources de polices. La fenêtre Nouveau fichier de ressources apparaît.
2.) Entrez le nom du fichier , puis cliquez sur OK. Le nouveau XML de ressource de police s’ouvre dans l’éditeur.
3.) Incluez chaque fichier de police, style et attribut de pondération dans l'élément balise font. Le code XML suivant illustre l'ajout d'attributs liés aux polices dans le code XML de la ressource de police:

<?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/hey_regular" />
    <font
    Android:fontStyle="italic"
    Android:fontWeight="400"
    Android:font="@font/hey_bababa" />
</font-family>

Ajout de polices à un TextView:

   <TextView
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    **Android:fontFamily="@font/ba_ba"**/>

À partir de la documentation 

Travailler avec les polices

toutes les étapes sont correctes.

7
jeevan s

Utiliser DataBinding :

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

le fichier de police doit être en assets/fonts/

7
Chulo

Si vous souhaitez uniquement ajouter un caractère et souhaitez utiliser moins de code, vous pouvez créer un TextView dédié à votre police. Voir le code ci-dessous.

package com.yourpackage;
import Android.content.Context;
import Android.graphics.Typeface;
import Android.util.AttributeSet;
import Android.widget.TextView;

public class FontTextView extends TextView {
    public static Typeface FONT_NAME;


    public FontTextView(Context context) {
        super(context);
        if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
        this.setTypeface(FONT_NAME);
    }
    public FontTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
        this.setTypeface(FONT_NAME);
    }
    public FontTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
        this.setTypeface(FONT_NAME);
    }
}

Dans main.xml, vous pouvez maintenant ajouter votre textView comme ceci:

<com.yourpackage.FontTextView
    Android:id="@+id/tvTimer"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:text="" />
7
Tore Rudberg

Étendez TextView et attribuez-lui un attribut personnalisé ou utilisez simplement l'attribut Android: tag pour transmettre une chaîne de la police que vous souhaitez utiliser. Vous devrez choisir une convention et vous y tenir, par exemple en plaçant toutes mes polices dans le dossier res/assets/fonts/afin que votre classe TextView sache où les trouver. Ensuite, dans votre constructeur, vous venez de définir la police manuellement après le super appel. 

5
schwiz

Le seul moyen d'utiliser des polices personnalisées est d'utiliser le code source.

N'oubliez pas qu'Android fonctionne sur des appareils disposant de ressources très limitées et que les polices peuvent nécessiter une bonne quantité de RAM. Les polices Droid intégrées sont spécialement conçues et, si vous remarquez, beaucoup de caractères et de décorations sont manquants.

4
Tareq Sha

Je pourrais avoir une réponse simple à la question sans étendre le TextView et implémenter un code long.

Code:

 TextView tv = (TextView) findViewById(R.id.textview1);
    tv.setTypeface(Typeface.createFromAsset(getAssets(), "font.ttf"));

Placez le fichier de police personnalisé dans le dossier des ressources comme d'habitude et essayez ceci. Cela fonctionne pour moi . Je ne comprends tout simplement pas pourquoi Peter a donné un code aussi énorme pour cette chose simple ou il a donné sa réponse dans une ancienne version.

2
San

Peut également être défini dans le XML sans créer de classes personnalisées

style.xml

<style name="ionicons" parent="Android:TextAppearance">
    <!-- Custom Attr-->
    <item name="fontPath">fonts/ionicons.ttf</item>
</style>

activity_main.xml

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
              xmlns:app="http://schemas.Android.com/apk/res-auto"
              Android:layout_width="match_parent"
              Android:layout_height="match_parent"
              Android:orientation="vertical" >
    <Button
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:textAppearance="@style/ionicons"
        Android:text=""/>
</LinearLayout>

Une note rapide, car j'ai toujours oublié où mettre les polices. C'est que la police doit être à l'intérieur de assets et que ce dossier réside au même niveau que res et src, dans mon cas son assets/fonts/ionicons.ttf

Updated Ajout de la disposition racine car cette méthode nécessite xmlns:app="http://schemas.Android.com/apk/res-auto" pour fonctionner

Update 2 J'ai oublié une bibliothèque que j'ai déjà installée et appelée Calligraphy

2
norman784

Il existe deux façons de personnaliser les polices:

!!! ma police personnalisée dans assets/fonts/iran_sans.ttf

Voie 1: Refrection Typeface.class ||| meilleur moyen

appel FontsOverride.setDefaultFont () dans la classe étend Application. Ce code entraînera la modification de toutes les polices du logiciel, même des polices 

AppController.Java

public class AppController extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        //Initial Font
        FontsOverride.setDefaultFont(getApplicationContext(), "MONOSPACE", "fonts/iran_sans.ttf");

    }
}

FontsOverride.Java

public class FontsOverride {

    public static void setDefaultFont(Context context, String staticTypefaceFieldName, String fontAssetName) {
        final Typeface regular = Typeface.createFromAsset(context.getAssets(), fontAssetName);
        replaceFont(staticTypefaceFieldName, regular);
    }

    private static void replaceFont(String staticTypefaceFieldName, final Typeface newTypeface) {
        try {
            final Field staticField = Typeface.class.getDeclaredField(staticTypefaceFieldName);
            staticField.setAccessible(true);
            staticField.set(null, newTypeface);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

Voie 2: use setTypeface

pour une vue spéciale, appelez simplement setTypeface () pour changer de police.

CTextView.Java

public class CTextView extends TextView {

    public CTextView(Context context) {
        super(context);
        init(context,null);
    }

    public CTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public CTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.Lollipop)
    public CTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context,attrs);
    }

    public void init(Context context, @Nullable AttributeSet attrs) {

        if (isInEditMode())
            return;

        // use setTypeface for change font this view
        setTypeface(FontUtils.getTypeface("fonts/iran_sans.ttf"));

    }
}

FontUtils.Java

public class FontUtils {

    private static Hashtable<String, Typeface> fontCache = new Hashtable<>();

    public static Typeface getTypeface(String fontName) {
        Typeface tf = fontCache.get(fontName);
        if (tf == null) {
            try {
                tf = Typeface.createFromAsset(AppController.getInstance().getApplicationContext().getAssets(), fontName);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
            fontCache.put(fontName, tf);
        }
        return tf;
    }

}
1
Rasoul Miri

La réponse de Peter est la meilleure, mais elle peut être améliorée en utilisant le fichier styles.xml d'Android pour personnaliser vos polices pour toutes les vues de texte de votre application.

Mon code est ici

1
Jelle

Voici un tutoriel qui vous montre comment configurer une police personnalisée comme décrit par @peter: http://responsiveandroid.com/2012/03/15/custom-fonts-in-Android-widgets.html

il prend également en compte les éventuelles fuites de mémoire ala http://code.google.com/p/Android/issues/detail?id=9904 . Le didacticiel contient également un exemple permettant de définir une police personnalisée sur un bouton.

0
browep

Vous pouvez facilement créer une classe textview personnalisée: -

Donc, ce que vous devez faire en premier, créez la classe Custom textview qui a été étendue avec AppCompatTextView.

public class CustomTextView extends AppCompatTextView {
    private int mFont = FontUtils.FONTS_NORMAL;
    boolean fontApplied;

    public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, context);
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, context);
    }

    public CustomTextView(Context context) {
        super(context);
        init(null, context);
    }

    protected void init(AttributeSet attrs, Context cxt) {
        if (!fontApplied) {
            if (attrs != null) {
                mFont = attrs.getAttributeIntValue(
                        "http://schemas.Android.com/apk/res-auto", "Lato-Regular.ttf",
                        -1);
            }
            Typeface typeface = getTypeface();
            int typefaceStyle = Typeface.NORMAL;
            if (typeface != null) {
                typefaceStyle = typeface.getStyle();
            }
            if (mFont > FontUtils.FONTS) {
                typefaceStyle = mFont;
            }
            FontUtils.applyFont(this, typefaceStyle);
            fontApplied = true;
        }
    }
}

Maintenant, à chaque fois, la vue texte personnalisée appelle et nous obtiendrons la valeur int de l'attribut int fontValue = attrs.getAttributeIntValue("http://schemas.Android.com/apk/res-auto","Lato-Regular.ttf",-1).

Ou

Nous pouvons également obtenir getTypeface () de la vue que nous avons définie dans notre code XML (Android:textStyle="bold|normal|italic"). Alors fais ce que tu veux faire.

Maintenant, nous faisons FontUtils pour définir toute police .ttf dans notre vue.

public class FontUtils {

    public static final int FONTS = 1;
    public static final int FONTS_NORMAL = 2;
    public static final int FONTS_BOLD = 3;
    public static final int FONTS_BOLD1 = 4;

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

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

    public static void applyFont(TextView tv, int typefaceStyle) {

        Context cxt = tv.getContext();
        Typeface typeface;

        if(typefaceStyle == Typeface.BOLD_ITALIC) {
            typeface = FontUtils.getFonts(cxt, "FaktPro-Normal.ttf");
        }else if (typefaceStyle == Typeface.BOLD || typefaceStyle == SD_FONTS_BOLD|| typefaceStyle == FONTS_BOLD1) {
            typeface = FontUtils.getFonts(cxt, "FaktPro-SemiBold.ttf");
        } else if (typefaceStyle == Typeface.ITALIC) {
            typeface = FontUtils.getFonts(cxt, "FaktPro-Thin.ttf");
        } else {
            typeface = FontUtils.getFonts(cxt, "FaktPro-Normal.ttf");
        }
        if (typeface != null) {
            tv.setTypeface(typeface);
        }
    }
}
0
duggu

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

Vous pouvez appliquer une police personnalisée à l'ensemble de l'application de la manière suivante.

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

  2. Dans res/values/styles.xml, utilisez-le dans le thème de l'application . <style name="AppTheme" parent="{whatever you like}"> <item name="Android:fontFamily">@font/myfont</item> </style>

0
Vic