J'ai ajouté un fichier de police personnalisé à mon dossier assets/fonts. Comment l'utiliser à partir de mon XML?
Je peux l'utiliser à partir du code comme suit:
TextView text = (TextView) findViewById(R.id.textview03);
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Molot.otf");
text.setTypeface(tf);
Puis-je le faire à partir de XML en utilisant un attribut Android:typeface="/fonts/Molot.otf"
?
Réponse courte: Non. Android ne prend pas en charge l’application de polices personnalisées aux widgets de texte via XML.
Cependant, il existe une solution de contournement qui n'est pas terriblement difficile à mettre en œuvre.
Premier
Vous devrez définir votre propre style. Dans votre dossier/res/values, ouvrez/créez le fichier attrs.xml et ajoutez un objet déclarable-styleable, comme ceci:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FontText">
<attr name="typefaceAsset" format="string"/>
</declare-styleable>
</resources>
Seconde
En supposant que vous souhaitiez utiliser souvent ce widget, vous devez configurer un cache simple pour les objets chargés Typeface
, car leur chargement à partir de la mémoire à la volée peut prendre du temps. Quelque chose comme:
public class FontManager {
private static FontManager instance;
private AssetManager mgr;
private Map<String, Typeface> fonts;
private FontManager(AssetManager _mgr) {
mgr = _mgr;
fonts = new HashMap<String, Typeface>();
}
public static void init(AssetManager mgr) {
instance = new FontManager(mgr);
}
public static FontManager getInstance() {
if (instance == null) {
// App.getContext() is just one way to get a Context here
// getContext() is just a method in an Application subclass
// that returns the application context
AssetManager assetManager = App.getContext().getAssets();
init(assetManager);
}
return instance;
}
public Typeface getFont(String asset) {
if (fonts.containsKey(asset))
return fonts.get(asset);
Typeface font = null;
try {
font = Typeface.createFromAsset(mgr, asset);
fonts.put(asset, font);
} catch (Exception e) {
}
if (font == null) {
try {
String fixedAsset = fixAssetFilename(asset);
font = Typeface.createFromAsset(mgr, fixedAsset);
fonts.put(asset, font);
fonts.put(fixedAsset, font);
} catch (Exception e) {
}
}
return font;
}
private String fixAssetFilename(String asset) {
// Empty font filename?
// Just return it. We can't help.
if (TextUtils.isEmpty(asset))
return asset;
// Make sure that the font ends in '.ttf' or '.ttc'
if ((!asset.endsWith(".ttf")) && (!asset.endsWith(".ttc")))
asset = String.format("%s.ttf", asset);
return asset;
}
}
Celui-ci vous permettra d'utiliser les extensions de fichier .ttc, mais ce n'est pas testé.
Troisième
Créez une nouvelle classe qui sous-classe TextView
. Cet exemple particulier prend en compte le type de caractère XML défini (bold
, italic
, etc.) et l'applique à la police (en supposant que vous utilisez un fichier .ttc).
/**
* TextView subclass which allows the user to define a truetype font file to use as the view's typeface.
*/
public class FontText extends TextView {
public FontText(Context context) {
this(context, null);
}
public FontText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FontText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (isInEditMode())
return;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.FontText);
if (ta != null) {
String fontAsset = ta.getString(R.styleable.FontText_typefaceAsset);
if (!TextUtils.isEmpty(fontAsset)) {
Typeface tf = FontManager.getInstance().getFont(fontAsset);
int style = Typeface.NORMAL;
float size = getTextSize();
if (getTypeface() != null)
style = getTypeface().getStyle();
if (tf != null)
setTypeface(tf, style);
else
Log.d("FontText", String.format("Could not create a font from asset: %s", fontAsset));
}
}
}
}
Finalement
Remplacez les instances de TextView
dans votre code XML par le nom de classe qualifié complet. Déclarez votre espace de noms personnalisé, tout comme vous le feriez pour l’espace de noms Android. Notez que "typefaceAsset" doit pointer vers un fichier .ttf ou .ttc contenu dans votre répertoire/assets.
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:custom="http://schemas.Android.com/apk/res-auto"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<com.example.FontText
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:text="This is a custom font text"
custom:typefaceAsset="fonts/AvenirNext-Regular.ttf"/>
</RelativeLayout>
Voici un exemple de code qui fait cela. La police est définie dans une variable finale statique et le fichier de police se trouve dans le répertoire assets.
public class TextViewWithFont extends TextView {
public TextViewWithFont(Context context, AttributeSet attrs) {
super(context, attrs);
this.setTypeface(MainActivity.typeface);
}
public TextViewWithFont(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setTypeface(MainActivity.typeface);
}
public TextViewWithFont(Context context) {
super(context);
this.setTypeface(MainActivity.typeface);
}
}
Activity implémente LayoutInflater.Factory2 qui fournit des rappels sur chaque vue créée . Il est possible d'attribuer un style à TextView avec l'attribut Famille de polices personnalisée, de charger les polices de caractères à la demande et d'appeler automatiquement setTypeface les vues en texte instancié.
Malheureusement, en raison de la relation architecturale des instances Inflater par rapport aux activités et à Windows, l'approche la plus simple pour utiliser des polices personnalisées dans Android consiste à mettre en cache les polices chargées au niveau de l'application.
La base de code exemple est ici:
https://github.com/leok7v/Android-textview-custom-fonts
<style name="Baroque" parent="@Android:style/TextAppearance.Medium">
<item name="Android:layout_width">fill_parent</item>
<item name="Android:layout_height">wrap_content</item>
<item name="Android:textColor">#F2BAD0</item>
<item name="Android:textSize">14pt</item>
<item name="fontFamily">baroque_script</item>
</style>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:custom="http://schemas.Android.com/apk/res/custom.fonts"
Android:orientation="vertical"
Android:layout_width="fill_parent"
Android:layout_height="fill_parent"
>
<TextView
style="@style/Baroque"
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:text="@string/sample_text"
/>
résulte en
Créez votre TextView personnalisé pour appartenir à la police que vous souhaitez utiliser. Dans cette classe, j'utilise un champ statique mTypeface pour mettre en cache la police de caractères (pour de meilleures performances)
public class HeliVnTextView extends TextView {
/*
* Caches typefaces based on their file path and name, so that they don't have to be created every time when they are referenced.
*/
private static Typeface mTypeface;
public HeliVnTextView(final Context context) {
this(context, null);
}
public HeliVnTextView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public HeliVnTextView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
if (mTypeface == null) {
mTypeface = Typeface.createFromAsset(context.getAssets(), "HelveticaiDesignVnLt.ttf");
}
setTypeface(mTypeface);
}
}
En fichier XML:
<Java.example.HeliVnTextView
Android:id="@+id/textView1"
Android:layout_width="0dp"
... />
En classe Java:
HeliVnTextView title = new HeliVnTextView(getActivity());
title.setText(issue.getName());
UPDATE: https://github.com/chrisjenx/Calligraphy semble être un solution supérieure à cela.
Vous pouvez peut-être utiliser reflect pour injecter/pirater votre police dans la liste statique des polices disponibles lors de la création de votre application? Je suis intéressé par les commentaires des autres s'il s'agit d'un vraiment, vraiment une mauvaise idée ou s'il s'agit d'un excellente solution - il semble que ce soit l'un de ces extrêmes ...
J'ai été en mesure d'injecter mon caractère personnalisé dans la liste des caractères système avec mon propre nom de famille de polices, puis de spécifier ce nom de famille de polices personnalisé ("brush-script") comme valeur de Android: FontFamily sur un TextView standard travaillé sur mon LG G4 sous Android 6.0.
public class MyApplication extends Android.app.Application
{
@Override
public void onCreate()
{
super.onCreate();
Typeface font = Typeface.createFromAsset(this.getResources().getAssets(),"fonts/brush-script.ttf");
injectTypeface("brush-script", font);
}
private boolean injectTypeface(String fontFamily, Typeface typeface)
{
try
{
Field field = Typeface.class.getDeclaredField("sSystemFontMap");
field.setAccessible(true);
Object fieldValue = field.get(null);
Map<String, Typeface> map = (Map<String, Typeface>) fieldValue;
map.put(fontFamily, typeface);
return true;
}
catch (Exception e)
{
Log.e("Font-Injection", "Failed to inject typeface.", e);
}
return false;
}
}
Dans ma mise en page
<TextView
Android:id="@+id/name"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:text="Fancy Text"
Android:fontFamily="brush-script"/>
Ce n'est pas une bonne idée d'utiliser des polices personnalisées au format xml en raison de ce fait En d'autres termes, vous devez le faire par programme pour éviter la fuite de mémoire!
Je sais que c’est une vieille question, mais j’ai trouvé une solution beaucoup plus simple.
Commencez par déclarer votre TextView au format XML comme d'habitude . Placez votre police (TTF ou TTC) dans le dossier
app\src\main\actifs \
Ensuite, définissez simplement la police de caractères pour votre affichage texte dans votre méthode onCreate.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_name);
TextView textView = findViewById(R.id.my_textView);
Typeface typeface = Typeface.createFromAsset(getAssets(), "fontName.ttf");
textView.setTypeface(typeface);
}
Terminé.
Créez un dossier de polices dans les ressources et ajoutez toutes les polices requises.
public class CustomTextView extends TextView {
private static final String TAG = "TextView";
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(context, attrs);
}
public CustomTextView(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.CustomTextView);
String customFont = a.getString(R.styleable.CustomTextView_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}
public boolean setCustomFont(Context ctx, String fontName) {
Typeface typeface = null;
try {
if(fontName == null){
fontName = Constants.DEFAULT_FONT_NAME;
}
typeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/" + fontName);
} catch (Exception e) {
Log.e(TAG, "Unable to load typeface: "+e.getMessage());
return false;
}
setTypeface(typeface);
return true;
}
}
et ajouter un déclarable dans attrs.xml
<declare-styleable name="CustomTextView">
<attr name="customFont" format="string"/>
</declare-styleable>
puis ajoutez votre customFont like
app:customFont="arial.ttf"
La meilleure solution consiste à utiliser (enfin) une fonctionnalité de police personnalisée native en XML introduite par Google. Mais vous devez cibler l'API 26. Il supporte l'API 16+
https://developer.Android.com/guide/topics/ui/look-and-feel/fonts-in-xml
au lieu de xmlns: custom = "schemas.Android.com/tools"; vous devriez utiliser: xmlns: custom = "schemas.Android.com/apk/res-auto"; afin d’utiliser des attributs stylables… j’ai fait cette modification et elle fonctionne maintenant.