Uso de la fuente personalizada en Android TextView utilizando xml

He añadido un archivo de fuentes personalizadas a mi carpeta de recursos / fuentes. ¿Cómo lo uso desde mi XML?

Puedo usarlo del 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 incorporado para aplicar fuentes 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

Tendrá que definir su propio estilo. En su carpeta / res / values, abra / cree el archivo attrs.xml y añada un objeto declarable como:

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

Segundo

Suponiendo que desee utilizar este widget a menudo, debe configurar una caché simple para los objetos de tipo de Typeface cargados, ya que cargarlos de memoria en marcha puede llevar tiempo. Algo como:

 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() { 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 (StringUtils.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 las extensiones de archivo .ttc, pero no ha sido probado.

Tercero

Cree una nueva clase que subclases TextView . Este ejemplo particular toma 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 (!StringUtils.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 de clase totalmente calificado. Declare su espacio de nombres personalizado como lo haría con el espacio de nombres de Android. Tenga en cuenta que el "typefaceAsset" debe apuntar a un archivo .ttf o .ttc contenido en su directorio / assets.

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/tools" 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> 

Aquí está 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); } } 

La actividad implementa LayoutInflater.Factory2 que proporciona devoluciones de llamada en cada vista creada. Es posible diseñar el TextView con el atributo fontFamily personalizado, cargar los tipos de letra a petición y llamar a setTypeface a 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 sencillo es almacenar en caché las fuentes cargadas en el nivel de aplicación.

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

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

Resulta en

Introduzca aquí la descripción de la imagen

Cree su TextView personalizado pertenezca 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 el archivo xml:

 <java.example.HeliVnTextView android:id="@+id/textView1" android:layout_width="0dp" ... /> 

En clase java:

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

No es una buena idea utilizar fuentes personalizadas en xml debido a este hecho que es, hay que hacerlo mediante programación para evitar la pérdida de memoria!

UPDATE: https://github.com/chrisjenx/Caligraphy parece ser una solución superior a esto.


¿Tal vez usted puede utilizar la reflexión para inyectar / cortar su fuente en la lista estática de fuentes disponibles cuando se crea su aplicación? Estoy interesado en la retroalimentación de los demás si esto es una idea realmente, muy mala o si esto es una gran solución – parece que va a ser uno de esos extremos …

Fui capaz de inyectar mi tipo de letra personalizado en la lista de tipos de letra de sistema con mi propio nombre de familia de fuente, a continuación, especificando que el nombre de familia de la fuente personalizada ("brush-script") como el valor de android: FontFamily en un TextView estándar trabajó 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<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; } } 

En mi diseño

 <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Fancy Text" android:fontFamily="brush-script"/> 

En lugar de xmlns: custom = "schemas.android.com/tools"; Usted debe usar: xmlns: custom = "schemas.android.com/apk/res-auto"; Con el fin de utilizar atributos con estilo. Hice este cambio y ahora está funcionando.

Cree una carpeta de fuentes en los recursos y agregue todos los tipos de letra necesarios 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 añadir un declarable en attrs.xml

 <declare-styleable name="CustomTextView"> <attr name="customFont" format="string"/> </declare-styleable> 

Y luego agrega tu customFont como

 app:customFont="arial.ttf" 
  • Cómo agregar etiquetas en XML en Android?
  • ¿Por qué no se muestra mi aplicación en Google Play? Ahora publicado
  • Animación de diseños utilizando el atributo "animateLayoutChanges" en XML
  • ImageView está pixelado en dispositivos Android más antiguos
  • Analizar elementos de la lista de archivos XML con XML simple en Android
  • Sincronizar datos en el dispositivo con el servidor?
  • No se pudo inicializar LoginButton Facebook-sdk para android
  • Android, org.simpleframework.xml Existencia de persistencia, Elemento 'foo' ya se utiliza
  • Escapar de espacios en blanco Android strings.xml
  • El resultado es diferente.
  • Creación / uso de XML de diseño generado en tiempo de ejecución en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.