Usar fuente personalizada en Android TextView usando xml

He agregado un archivo de fuente personalizado a mi carpeta assets / fonts. ¿Cómo lo uso de mi XML?

Puedo usarlo desde el código de la siguiente manera:

TextView text = (TextView) findViewById(R.id.textview03); Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Molot.otf"); text.setTypeface(tf); 

¿No puedo hacerlo desde XML usando un atributo android:typeface="/fonts/Molot.otf" ?

Respuesta corta: No. Android no tiene soporte integrado para aplicar fonts personalizadas a widgets de texto a través de XML.

Sin embargo, hay una solución que no es terriblemente difícil de implementar.

primero

Deberá definir su propio estilo. En su carpeta / res / values, abra / cree el archivo attrs.xml y agregue un objeto declare-styleable de esta manera:

 < ?xml version="1.0" encoding="utf-8"?>      

Segundo

Suponiendo que quiera usar este widget con frecuencia, debe configurar un caché simple para los objetos cargados de Typeface , ya que cargarlos desde la memoria sobre la marcha puede llevar tiempo. Algo como:

 public class FontManager { private static FontManager instance; private AssetManager mgr; private Map fonts; private FontManager(AssetManager _mgr) { mgr = _mgr; fonts = new HashMap(); } 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; } } 

Éste le permitirá usar extensiones de archivo .ttc, pero no se ha probado.

Tercero

Crea una nueva clase que subclases TextView . Este ejemplo particular tiene en cuenta el tipo de letra XML definido ( bold , italic , etc.) y lo aplica a la fuente (suponiendo que esté utilizando un archivo .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)); } } } } 

Finalmente

Reemplace las instancias de TextView en su XML con el nombre completo de la clase. Declare su espacio de nombres personalizado al igual que lo haría con el espacio de nombres de Android. Tenga en cuenta que el “tipo de letraAsset” debe apuntar a un archivo .ttf o .ttc contenido en su directorio / assets.

    

Aquí hay un código de ejemplo que hace esto. Tengo la fuente definida en una variable final estática y el archivo de fuente está en el directorio de activos.

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

Cree su Customed TextView pertenece a la fuente que desea utilizar. En esta clase, utilizo un campo mTypeface estático para almacenar en caché el Typeface (para un mejor rendimiento)

 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 archivo xml:

  

En la clase de java:

 HeliVnTextView title = new HeliVnTextView(getActivity()); title.setText(issue.getName()); 

La actividad implementa LayoutInflater.Factory2 que proporciona devoluciones de llamada en cada vista creada. Es posible diseñar el TextView con el atributo personalizado fontFamily, cargar los tipos de letra según demanda y llamar a setTypeface en las vistas de texto instanciadas automáticamente.

Desafortunadamente, debido a la relación arquitectónica de las instancias de Inflater en relación con las actividades y Windows, el enfoque más simple es almacenar las fonts cargadas en el nivel de aplicación.

La base de código de muestra está aquí:

https://github.com/leok7v/android-textview-custom-fonts

   < ?xml version="1.0" encoding="utf-8"?>   

resultados en

enter image description here

No es una buena idea usar fonts personalizadas en xml debido a este hecho , es decir, debe hacerlo programáticamente para evitar la pérdida de memoria.

ACTUALIZACIÓN: https://github.com/chrisjenx/Calligraphy parece ser una solución superior a esto.


¿Tal vez puede usar el reflection para inyectar / piratear su fuente en la lista estática de fonts disponibles cuando se crea su aplicación? Estoy interesado en los comentarios de los demás si esta es una idea muy, muy mala o si esta es una gran solución , parece que va a ser uno de esos extremos …

Pude inyectar mi tipo de letra personalizado en la lista de tipos de letra del sistema con mi propio nombre de fuente, luego especifiqué ese nombre de familia de fuente personalizado (“brush-script”) como el valor de android: FontFamily en un TextView estándar trabajado en mi LG G4 con 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 map = (Map) fieldValue; map.put(fontFamily, typeface); return true; } catch (Exception e) { Log.e("Font-Injection", "Failed to inject typeface.", e); } return false; } } 

En mi diseño

  

Sé que esta es una vieja pregunta, pero he encontrado una solución mucho más fácil.

Primero declare su TextView en xml como de costumbre. Coloque su fuente (TTF o TTC) en la carpeta de activos

aplicación \ src \ main \ assets \

Luego, simplemente configure el tipo de letra para su vista de texto en su método 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); } 

Hecho.

Cree una carpeta de fonts en los activos y agregue todas las fonts requeridas allí.

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

y agregue un declarable en attrs.xml

    

y luego agrega tuFuente personalizado como

 app:customFont="arial.ttf" 

en lugar de xmlns: custom = “schemas.android.com/tools”; debe usar: xmlns: custom = “schemas.android.com/apk/res-auto”; para usar atributos de estilo. Hice este cambio y está funcionando ahora.