Utiliser des polices personnalisées

Le but de ce tutoriel est d’expliquer les différentes étapes permettant d’inclurent des polices personnalisées dans une application Android.

Inclure les polices dans un projet Android Studio

Afin d’utiliser les polices TTF sur Android, il vous faudra les ajouter dans les assets. Ce dossier permet d’inclure des fichiers de toutes sortes dans notre APK. Ils ne seront pas “compilés” (cf ressources et fichier R.java) et accessible directement via la méthode getAssets().

Nous allons créer le dossier assets directement dans le dossier main/, puis nous allons y placer le dossier font/ (qui contiendra la liste des polices TTF).

Capture d’écran 2015-06-30 à 16.55.25

 

La seconde étape consiste à modifier la police d’un composant (TextView par exemple) et cela de deux manières différentes (depuis le code Java / depuis les layouts)

1. Depuis le code Java

Vous pouvez facilement récupérer une police (font) depuis une activité / fragment ou autre emplacement (tant que vous disposez d’un contexte). Cela à l’aide de la fonction Typeface.createFromAsset(getAssets(), FICHIER_DE_LA_POLICE);
Si nous travaillons avec le layout suivant

layout/activity_main

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <TextView
        android:id="@+id/text1"
        android:layout_margin="10dp"
        android:textSize="25sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Police normal" />

    <TextView
        android:id="@+id/text2"
        android:layout_margin="10dp"
        android:textSize="25sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Police personnalisée" />

    <TextView
        android:id="@+id/text3"
        android:layout_margin="10dp"
        android:textSize="25sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Police personnalisée" />

</LinearLayout>

Nous pouvons facilement personnaliser la police des textview comme ci-dessous:

MainActivity.java

public class MainActivity extends AppCompatActivity {

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

        TextView textView1 = (TextView) findViewById(R.id.text1);
        TextView textView2 = (TextView) findViewById(R.id.text2);
        TextView textView3 = (TextView) findViewById(R.id.text3);

        setFont(textView2,"CURSTOM-FONT1.ttf");
        setFont(textView3,"CURSTOM-FONT2.ttf");
    }

    public void setFont(TextView textView, String fontName) {
        if(fontName != null){
            try {
                Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/" + fontName);
                textView.setTypeface(typeface);
            } catch (Exception e) {
                Log.e("FONT", fontName + " not found", e);
            }
        }
    }
}

Ce qui donnera le résultat suivant

device-2015-06-30-170718-1024x867

2. Depuis les layouts

Une seconde méthode, ma préférée, consiste à surcharger le composant ciblé (ici TextView) afin de créer une version acceptant un attribut font. Cet attribut indiquera quelle police utiliser. Nous appellerons cette vue CustomTextView

Il faut commencer par définir un attribut font, utilisable par notre CustomTextView :

(créer le fichier attrs.xml dans le dossier values)

values/attrs.xml

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

Puis créer la classe qui surcharge la classe TextView. Elle sera capable de récupérer l’attribut font et l’utiliser comme police :

CustomTextView.java

public class CustomTextView extends TextView {

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

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

        //accède aux attributs ajoutés à cette CustomTextView
        TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView);

        //récupère l'attribut "font"
        String fontName = styledAttrs.getString(R.styleable.CustomTextView_font);

        //permet au garbage collector de récupérer l'espace utilisé par ce TypedArray
        styledAttrs.recycle();

        //puis modifie la font de cet élément
        setTypeFace(fontName);
    }

    public void setTypeFace(String fontName) {
        if(fontName != null){
            try {
                Typeface typeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/" + fontName);
                setTypeface(typeface);
            } catch (Exception e) {
                Log.e("FONT", fontName + " not found", e);
            }
        }
    }

}

L’activité délègue la gestion des polices à une classe spécifique.

MainActivity.java

public class MainActivity extends AppCompatActivity {

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

}

Son utilisation depuis le layout XML se fait simplement (penser à précéder CustomTextView par votre nom de package)

layout/activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <TextView
        android:id="@+id/text1"
        android:layout_margin="10dp"
        android:textSize="25sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Police normal" />

    <com.tutosandroidfrance.customfont.CustomTextView
        android:id="@+id/text2"
        android:layout_margin="10dp"
        android:textSize="25sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Police personnalisée"
        app:font="Roboto-Light.ttf"/>

    <com.tutosandroidfrance.customfont.CustomTextView
        android:id="@+id/text3"
        android:layout_margin="10dp"
        android:textSize="25sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Police personnalisée"
        app:font="Roboto-Black.ttf"/>

</LinearLayout>

device-2015-06-30-170718-1024x867

Amélioration

Le chargement d’une font ainsi que son stockage sont assez couteux, en terme de performance ou de mérmoire. Une optimisation possible est de stocker les fonts dans un cache, ici nommés LruCache :

public class CustomTextView extends TextView {

    //créé un cache de Typeface, pouvant contenir 12 fonts
    private static LruCache<String, Typeface> TYPEFACE_CACHE = new LruCache<String, Typeface>(12);

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

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

        //accède aux attributs ajoutés à cette CustomTextView
        TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView);

        //récupère l'attribut "font"
        String fontName = styledAttrs.getString(R.styleable.CustomTextView_font);

        //permet au garbage collector de récupérer l'espace utilisé par ce TypedArray
        styledAttrs.recycle();

        //puis modifie la font de cet élément
        setTypeFace(fontName);
    }

    public void setTypeFace(String fontName) {
        if(fontName != null){
            try {
                //on regarde dans le cache si cette police est présente
                Typeface typeface = TYPEFACE_CACHE.get(fontName);
            
                //si non, on la charge à partir des assets
                if (typeface == null) {
                    typeface = Typeface.createFromAsset(getContext().getAssets(),"fonts/" + fontName);

                    //puis on la sauvegarde dans notre cache
                    TYPEFACE_CACHE.put(fontName, typeface);
                }

                //puis on l'utilise sur notre TextView
                setTypeface(typeface);
            } catch (Exception e) {
                Log.e("FONT", fontName + " not found", e);
            }
        }
    }

}

Les sources de ce tutoriel sont disponibles sur github :

version activité

version custom view

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *