Usar un tipo de letra personalizado en Android


111

Quiero usar una fuente personalizada para mi aplicación de Android que estoy creando.
Puedo cambiar individualmente el tipo de letra de cada objeto desde Code, pero tengo cientos de ellos.

Entonces,

  • ¿Hay alguna forma de hacer esto desde XML? [Configuración de un tipo de letra personalizado]
  • ¿Hay alguna manera de hacerlo desde el código en un solo lugar, para decir que toda la aplicación y todos los componentes deben usar el tipo de letra personalizado en lugar del predeterminado?

stackoverflow.com/questions/5541058/… Mira esta publicación Publiqué el código completo aquí con respecto a este problema
Manish Singla

Puede usar variables estáticas en su actividad principal para mantener referencias a las fuentes incrustadas. Eso haría que hubiera un conjunto persistente de fuentes que GC no recogería.
Jacksonkr

Método de fábrica. O un método que tome su punto de vista y establezca todas las configuraciones de fuente y tipografía.
mtmurdock

La nueva biblioteca de soporte 26 ahora le permite usar fuentes en XML. Así es como se hace Fuentes en XML
Vinicius Silva

Respuestas:


80

¿Hay alguna forma de hacer esto desde XML?

No lo siento. Solo puede especificar los tipos de letra integrados a través de XML.

¿Hay alguna manera de hacerlo desde el código en un solo lugar, para decir que toda la aplicación y todos los componentes deben usar el tipo de letra personalizado en lugar del predeterminado?

No que yo sepa.

Hay una variedad de opciones para estos hoy en día:

  • Recursos de fuentes y backports en el SDK de Android, si está utilizando appcompat

  • Bibliotecas de terceros para quienes no las utilizan appcompat, aunque no todas admitirán la definición de la fuente en los recursos de diseño


4
@Codevalley: Bueno, en muchos sentidos, la mejor respuesta es no preocuparse por las fuentes personalizadas. Suelen ser grandes, lo que aumenta las descargas y reduce la cantidad de personas que descargarán y seguirán usando su aplicación.
CommonsWare

22
@CommonsWare: No necesariamente estoy de acuerdo. El tipo de letra es una parte integral del estilo de la interfaz de usuario como lo hace con las imágenes de fondo, etc. Y el tamaño no siempre es necesariamente grande. Por ejemplo, la fuente en mi caso es solo 19.6KB :)
Codevalley

2
@Amit: No ha habido cambios en este tema. Hay muchos fragmentos de código para ayudar a simplificar la aplicación de un tipo de letra a su interfaz de usuario en Java, pero no hay forma de hacerlo desde XML.
CommonsWare

1
@Amit: "¿Pero eso significa que tendré que crear mis propios archivos .ttf o .otf para fuentes personalizadas?" -- mmm no. Puede utilizar fuentes TTF / OTF existentes, aunque es posible que no todas funcionen. El problema en esta pregunta es cómo aplicar esas fuentes en toda una aplicación, lo que aún no es posible, y eso es a lo que me refería en mi comentario.
CommonsWare

1
Esta respuesta aceptada es obsoleta y sería genial actualizarla o eliminarla.
Sky Kelsey

109

Sí, es posible.

Tienes que crear una vista personalizada que amplíe la vista de texto.

En attrs.xmlen valuescarpeta:

<resources>
    <declare-styleable name="MyTextView">
        <attr name="first_name" format="string"/>
        <attr name="last_name" format="string"/>
        <attr name="ttf_name" format="string"/>
    </declare-styleable>
</resources>

En main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:lht="http://schemas.android.com/apk/res/com.lht"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TextView  android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="Hello"/>
    <com.lht.ui.MyTextView  
        android:id="@+id/MyTextView"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="Hello friends"
        lht:ttf_name="ITCBLKAD.TTF"
        />   
</LinearLayout>

En MyTextView.java:

package com.lht.ui;

import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class MyTextView extends TextView {

    Context context;
    String ttfName;

    String TAG = getClass().getName();

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;

        for (int i = 0; i < attrs.getAttributeCount(); i++) {
            Log.i(TAG, attrs.getAttributeName(i));
            /*
             * Read value of custom attributes
             */

            this.ttfName = attrs.getAttributeValue(
                    "http://schemas.android.com/apk/res/com.lht", "ttf_name");
            Log.i(TAG, "firstText " + firstText);
            // Log.i(TAG, "lastText "+ lastText);

            init();
        }

    }

    private void init() {
        Typeface font = Typeface.createFromAsset(context.getAssets(), ttfName);
        setTypeface(font);
    }

    @Override
    public void setTypeface(Typeface tf) {

        // TODO Auto-generated method stub
        super.setTypeface(tf);
    }

}

4
Esto funcionará, pero solo para TextView. Requerirá subclases personalizadas para cada clase de widget que herede de TextViewdonde se desea la misma capacidad.
CommonsWare

Hola Manish, gracias por la solución. Aunque estoy enfrentando un problema al usar esto. Sigo obteniendo 'no se encontró ningún identificador de recurso para el atributo ttf_name en el paquete com.lht.android'
Kshitij Aggarwal

17
Esto funcionará, pero antes de ICS asignará memoria para las fuentes para cada vista que instales : code.google.com/p/android/issues/detail?id=9904 Una forma de solucionar esto es crear un acceso global hashmap estático de todas las fuentes instanciadas: code.google.com/p/android/issues/detail?id=9904#c7
Ken Van Hoeylandt

¿Por qué necesitamos un bucle ?, ¿no debería funcionar con una sola llamada?
Guillermo Tobar

1
@AlaksiejN. en caso de que necesite establecer diferentes tipos de letra para diferentes TextViews ...
Nick

49

Hice esto de una manera más "de fuerza bruta" que no requiere cambios en el diseño XML o Actividades.

Probado en la versión de Android 2.1 a 4.4. Ejecute esto al iniciar la aplicación, en su clase de aplicación:

private void setDefaultFont() {

    try {
        final Typeface bold = Typeface.createFromAsset(getAssets(), DEFAULT_BOLD_FONT_FILENAME);
        final Typeface italic = Typeface.createFromAsset(getAssets(), DEFAULT_ITALIC_FONT_FILENAME);
        final Typeface boldItalic = Typeface.createFromAsset(getAssets(), DEFAULT_BOLD_ITALIC_FONT_FILENAME);
        final Typeface regular = Typeface.createFromAsset(getAssets(),DEFAULT_NORMAL_FONT_FILENAME);

        Field DEFAULT = Typeface.class.getDeclaredField("DEFAULT");
        DEFAULT.setAccessible(true);
        DEFAULT.set(null, regular);

        Field DEFAULT_BOLD = Typeface.class.getDeclaredField("DEFAULT_BOLD");
        DEFAULT_BOLD.setAccessible(true);
        DEFAULT_BOLD.set(null, bold);

        Field sDefaults = Typeface.class.getDeclaredField("sDefaults");
        sDefaults.setAccessible(true);
        sDefaults.set(null, new Typeface[]{
                regular, bold, italic, boldItalic
        });

    } catch (NoSuchFieldException e) {
        logFontError(e);
    } catch (IllegalAccessException e) {
        logFontError(e);
    } catch (Throwable e) {
        //cannot crash app if there is a failure with overriding the default font!
        logFontError(e);
    }
}

Para obtener un ejemplo más completo, consulte http://github.com/perchrh/FontOverrideExample


Esta es la mejor solución para mí.
Igor K

2
por defecto no funciona para mí. si utilizo monospace y luego configuro code<style name = "AppTheme" parent = "AppBaseTheme"> <item name = "android: typeface"> monospace </item> </style> code, funciona pero no para negrita. Agregué este código en una clase que extiende Application. ¿Es ese el lugar correcto? @ P-chan
Christopher Rivera

2
@ChristopherRivera Sí, agréguelo a la clase Application de su aplicación, asegúrese de que se ejecute en onCreate. Echando un vistazo a grepcode.com/file/repository.grepcode.com/java/ext/… ¡ Le sugiero que anule el campo adicional para monoespacio, así como el de mi código de muestra anterior!
Por Christian Henden

2
Bien, cambié por el campo SERIF y funcionó :)
Abdullah Umer

3
Esta respuesta hace referencia a esta respuesta y proporciona un enfoque más limpio en mi humilde opinión.
Adamdport

36

Aunque estoy votando positivamente la respuesta de Manish como el método más rápido y más específico, también he visto soluciones ingenuas que simplemente iteran recursivamente a través de una jerarquía de vistas y actualizan los tipos de letra de todos los elementos a su vez. Algo como esto:

public static void applyFonts(final View v, Typeface fontToSet)
{
    try {
        if (v instanceof ViewGroup) {
            ViewGroup vg = (ViewGroup) v;
            for (int i = 0; i < vg.getChildCount(); i++) {
                View child = vg.getChildAt(i);
                applyFonts(child, fontToSet);
            }
        } else if (v instanceof TextView) {
            ((TextView)v).setTypeface(fontToSet);
        }
    } catch (Exception e) {
        e.printStackTrace();
        // ignore
    }
}

Debería llamar a esta función en sus vistas después de inflar el diseño y en los onContentChanged()métodos de su Actividad .


Bastante. En ese momento, era la única forma de hacerlo dentro de los plazos del proyecto. Un atajo útil si es necesario (:
pospi

23

Pude hacer esto de manera centralizada, aquí está el resultado:

ingrese la descripción de la imagen aquí

Tengo lo siguiente Activityy lo extiendo si necesito fuentes personalizadas:

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater.Factory;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class CustomFontActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    getLayoutInflater().setFactory(new Factory() {

        @Override
        public View onCreateView(String name, Context context,
                AttributeSet attrs) {
            View v = tryInflate(name, context, attrs);
            if (v instanceof TextView) {
                setTypeFace((TextView) v);
            }
            return v;
        }
    });
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

private View tryInflate(String name, Context context, AttributeSet attrs) {
    LayoutInflater li = LayoutInflater.from(context);
    View v = null;
    try {
        v = li.createView(name, null, attrs); 
    } catch (Exception e) {
        try {
            v = li.createView("android.widget." + name, null, attrs);
        } catch (Exception e1) {
        }
    }
    return v;
}

private void setTypeFace(TextView tv) {
    tv.setTypeface(FontUtils.getFonts(this, "MTCORSVA.TTF"));
}
}

Pero si estoy usando una actividad del paquete de soporte, por ejemplo, FragmentActivityentonces uso esto Activity:

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class CustomFontFragmentActivity extends FragmentActivity {

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

// we can't setLayout Factory as its already set by FragmentActivity so we
// use this approach
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    View v = super.onCreateView(name, context, attrs);
    if (v == null) {
        v = tryInflate(name, context, attrs);
        if (v instanceof TextView) {
            setTypeFace((TextView) v);
        }
    }
    return v;
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public View onCreateView(View parent, String name, Context context,
        AttributeSet attrs) {
    View v = super.onCreateView(parent, name, context, attrs);
    if (v == null) {
        v = tryInflate(name, context, attrs);
        if (v instanceof TextView) {
            setTypeFace((TextView) v);
        }
    }
    return v;
}

private View tryInflate(String name, Context context, AttributeSet attrs) {
    LayoutInflater li = LayoutInflater.from(context);
    View v = null;
    try {
        v = li.createView(name, null, attrs);
    } catch (Exception e) {
        try {
            v = li.createView("android.widget." + name, null, attrs);
        } catch (Exception e1) {
        }
    }
    return v;
}

private void setTypeFace(TextView tv) {
    tv.setTypeface(FontUtils.getFonts(this, "MTCORSVA.TTF"));
}
}

No he probado este código con Fragment s todavía, pero espero que funcione.

Mi FontUtilses simple, que también resuelve el problema anterior a ICS mencionado aquí https://code.google.com/p/android/issues/detail?id=9904 :

import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.graphics.Typeface;

public class FontUtils {

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

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

2
Esto debería obtener más votos. Funciona y tiene una captura de pantalla para demostración
ericn

10

¡Oye, también necesito 2 fuentes diferentes en mi aplicación para diferentes widgeds! Yo uso de esta manera:

En mi clase de aplicación creo un método estático:

public static Typeface getTypeface(Context context, String typeface) {
    if (mFont == null) {
        mFont = Typeface.createFromAsset(context.getAssets(), typeface);
    }
    return mFont;
}

El tipo de letra String representa el xyz.ttf en la carpeta de activos. (Creé una clase de constantes) Ahora puedes usar esto en cualquier lugar de tu aplicación:

mTextView = (TextView) findViewById(R.id.text_view);
mTextView.setTypeface(MyApplication.getTypeface(this, Constants.TYPEFACE_XY));

El único problema es que lo necesita para cada widget en el que desee utilizar la fuente. Pero creo que esta es la mejor manera.


4

Usando la sugerencia de pospi y trabajando con la propiedad 'etiqueta' como Richard hizo , creé una clase personalizada que carga mis fuentes personalizadas y las aplica a las vistas de acuerdo con sus etiquetas.

Entonces, básicamente, en lugar de configurar TypeFace en el atributo android: fontFamily, está utilizando el atributo android: tag y configúrelo en una de las enumeraciones definidas.

public class Fonts {
    private AssetManager mngr;

    public Fonts(Context context) {
        mngr = context.getAssets();
    }
    private enum AssetTypefaces {
        RobotoLight,
        RobotoThin,
        RobotoCondensedBold,
        RobotoCondensedLight,
        RobotoCondensedRegular
    }

    private Typeface getTypeface(AssetTypefaces font) {
        Typeface tf = null;
        switch (font) {
            case RobotoLight:
                tf = Typeface.createFromAsset(mngr,"fonts/Roboto-Light.ttf");
                break;
            case RobotoThin:
                tf = Typeface.createFromAsset(mngr,"fonts/Roboto-Thin.ttf");
                break;
            case RobotoCondensedBold:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Bold.ttf");
                break;
            case RobotoCondensedLight:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Light.ttf");
                break;
            case RobotoCondensedRegular:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Regular.ttf");
                break;
            default:
                tf = Typeface.DEFAULT;
                break;
        }
        return tf;
    }
    public void setupLayoutTypefaces(View v) {
        try {
            if (v instanceof ViewGroup) {
                ViewGroup vg = (ViewGroup) v;
                for (int i = 0; i < vg.getChildCount(); i++) {
                    View child = vg.getChildAt(i);
                    setupLayoutTypefaces(child);
                }
            } else if (v instanceof TextView) {
                if (v.getTag().toString().equals(AssetTypefaces.RobotoLight.toString())){
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoLight));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedRegular.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedRegular));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedBold.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedBold));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedLight.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedLight));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoThin.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoThin));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            // ignore
        }
    }
}

En tu Actividad o Fragmento solo llamas

Fonts fonts = new Fonts(getActivity());
fonts.setupLayoutTypefaces(mainLayout);

4

Encontré una buena solución en el blog de Lisa Wray . Con el nuevo enlace de datos, es posible establecer la fuente en sus archivos XML.

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

¿Puede sugerir un ejemplo con el enlace de datos? Eso sería muy apreciado.
Sri Krishna

3

Creo que puede haber una forma más práctica de hacerlo. La siguiente clase establecerá un tipo de letra personalizado para todos los componentes de su aplicación (con una configuración por clase).

/**
 * Base Activity of our app hierarchy.
 * @author SNI
 */
public class BaseActivity extends Activity {

    private static final String FONT_LOG_CAT_TAG = "FONT";
    private static final boolean ENABLE_FONT_LOGGING = false;

    private Typeface helloTypeface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        helloTypeface = Typeface.createFromAsset(getAssets(), "fonts/<your type face in assets/fonts folder>.ttf");
    }

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        View view = super.onCreateView(name, context, attrs);
        return setCustomTypeFaceIfNeeded(name, attrs, view);
    }

    @Override
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
        View view = super.onCreateView(parent, name, context, attrs);
        return setCustomTypeFaceIfNeeded(name, attrs, view);
    }

    protected View setCustomTypeFaceIfNeeded(String name, AttributeSet attrs, View view) {
        View result = null;
        if ("TextView".equals(name)) {
            result = new TextView(this, attrs);
            ((TextView) result).setTypeface(helloTypeface);
        }

        if ("EditText".equals(name)) {
            result = new EditText(this, attrs);
            ((EditText) result).setTypeface(helloTypeface);
        }

        if ("Button".equals(name)) {
            result = new Button(this, attrs);
            ((Button) result).setTypeface(helloTypeface);
        }

        if (result == null) {
            return view;
        } else {
            if (ENABLE_FONT_LOGGING) {
                Log.v(FONT_LOG_CAT_TAG, "A type face was set on " + result.getId());
            }
            return result;
        }
    }

}

2

Las implementaciones predeterminadas de LayoutInflater no admiten la especificación del tipo de letra de xml. Sin embargo, lo he visto hecho en xml al proporcionar una fábrica personalizada para LayoutInflater que analizará dichos atributos de la etiqueta xml.

A la estructura básica le gustaría esto.

public class TypefaceInflaterFactory implements LayoutInflater.Factory {

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        // CUSTOM CODE TO CREATE VIEW WITH TYPEFACE HERE
        // RETURNING NULL HERE WILL TELL THE INFLATER TO USE THE
        // DEFAULT MECHANISMS FOR INFLATING THE VIEW FROM THE XML
    }

}

public class BaseActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater.from(this).setFactory(new TypefaceInflaterFactory());
    }
}

Este artículo proporciona una explicación más detallada de estos mecanismos y cómo el autor intenta proporcionar soporte de diseño xml para tipos de letra de esta manera. El código para la implementación del autor se puede encontrar aquí .


1

Establecer una fuente personalizada a un ProgressDialog / AlertDialog regular:

font=Typeface.createFromAsset(getAssets(),"DroidSans.ttf");

ProgressDialog dialog = ProgressDialog.show(this, "titleText", "messageText", true);
((TextView)dialog.findViewById(Resources.getSystem().getIdentifier("message", "id", "android"))).setTypeface(font);
((TextView)dialog.findViewById(Resources.getSystem().getIdentifier("alertTitle", "id", "android"))).setTypeface(font);

1

Sí, es posible anulando el tipo de letra predeterminado. Seguí esta solución y funcionó como un encanto para todos los textos de TextViews y ActionBar también con un solo cambio.

public class MyApp extends Application {

  @Override
  public void onCreate() {
    TypefaceUtil.overrideFont(getApplicationContext(), "SERIF", "fonts/Roboto-Regular.ttf"); // font from assets: "assets/fonts/Roboto-Regular.ttf
  }
}

styles.xml

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/pantone</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowTranslucentStatus" tools:targetApi="kitkat">true</item>
    <item name="android:windowDisablePreview">true</item>
    <item name="android:typeface">serif</item>
</style>

En lugar de themes.xml como se menciona en el enlace anterior, mencioné la fuente predeterminada para anular en mi styles.xml en la etiqueta de tema de mi aplicación predeterminada. Los tipos de letra predeterminados que se pueden sobrescribir son serif, sans, monospace y normal.

TypefaceUtil.java

public class TypefaceUtil {

    /**
     * Using reflection to override default typeface
     * NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE OVERRIDDEN
     * @param context to work with assets
     * @param defaultFontNameToOverride for example "monospace"
     * @param customFontFileNameInAssets file name of the font from assets
     */
    public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
        try {
            final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);

            final Field defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
            defaultFontTypefaceField.setAccessible(true);
            defaultFontTypefaceField.set(null, customFontTypeface);
        } catch (Exception e) {
            Log.e("Can not set custom font " + customFontFileNameInAssets + " instead of " + defaultFontNameToOverride);
        }
    }
}

Inicialmente, no sabía que los tipos de letra que se sobrescribían son fijos y tienen valores definidos, pero finalmente me ayudó a comprender cómo trata Android las fuentes y los tipos de letra y sus valores predeterminados, que es un punto diferente por supuesto.


0

No sé si cambia toda la aplicación, pero he logrado cambiar algunos componentes que de otra manera no se podrían cambiar haciendo esto:

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Lucida Sans Unicode.ttf");
Typeface.class.getField("DEFAULT").setAccessible(true);
Typeface.class.getField("DEFAULT_BOLD").setAccessible(true);
Typeface.class.getField("DEFAULT").set(null, tf);
Typeface.class.getField("DEFAULT_BOLD").set(null, tf);

2
Desafortunadamente, esto ya no funciona: java.lang.IllegalAccessException: el campo está marcado como 'final' en java.lang.reflect.Field.setField (método nativo) en java.lang.reflect.Field.set (Field.java: 556)
BoD

0

Me gusta la sugerencia de pospi. ¿Por qué no usar la propiedad 'etiqueta' de una vista (que puede especificar en XML - 'android: etiqueta') para especificar cualquier estilo adicional que no pueda hacer en XML? Me gusta JSON, así que usaría una cadena JSON para especificar un conjunto de clave / valor. Esta clase hace el trabajo, solo llame Style.setContentView(this, [resource id])a su actividad.

public class Style {

  /**
   * Style a single view.
   */
  public static void apply(View v) {
    if (v.getTag() != null) {
      try {
        JSONObject json = new JSONObject((String)v.getTag());
        if (json.has("typeface") && v instanceof TextView) {
          ((TextView)v).setTypeface(Typeface.createFromAsset(v.getContext().getAssets(),
                                                             json.getString("typeface")));
        }
      }
      catch (JSONException e) {
        // Some views have a tag without it being explicitly set!
      }
    }
  }

  /**
   * Style the passed view hierarchy.
   */
  public static View applyTree(View v) {
    apply(v);
    if (v instanceof ViewGroup) {
      ViewGroup g = (ViewGroup)v;
      for (int i = 0; i < g.getChildCount(); i++) {
        applyTree(g.getChildAt(i));
      }
    }
    return v;
  }

  /**
   * Inflate, style, and set the content view for the passed activity.
   */
  public static void setContentView(Activity activity, int resource) {
    activity.setContentView(applyTree(activity.getLayoutInflater().inflate(resource, null)));
  }
}

Obviamente, querrá manejar más que solo el tipo de letra para que valga la pena usar JSON.

Una ventaja de la propiedad 'etiqueta' es que puede establecerla en un estilo base que usa como tema y, por lo tanto, hacer que se aplique a todas sus vistas automáticamente. EDITAR: Hacer esto da como resultado un bloqueo durante la inflación en Android 4.0.3. Aún puede usar un estilo y aplicarlo a las vistas de texto individualmente.

Una cosa que verá en el código, algunas vistas tienen una etiqueta sin que se establezca una explícitamente, extrañamente es la cadena 'Αποκοπή', que está 'cortada' en griego, según el traductor de Google. Que demonios...?


0

La respuesta de @ majinboo se revisó para la gestión del rendimiento y la memoria. Cualquier actividad relacionada con la necesidad de más de una fuente puede usar esta clase de fuente dando el propio constructor como parámetro.

@Override
public void onCreate(Bundle savedInstanceState)
{
    Font font = new Font(this);
}

La clase de fuentes revisadas es la siguiente:

public class Fonts
{
    private HashMap<AssetTypefaces, Typeface> hashMapFonts;

    private enum AssetTypefaces
    {
        RobotoLight,
        RobotoThin,
        RobotoCondensedBold,
        RobotoCondensedLight,
        RobotoCondensedRegular
    }

    public Fonts(Context context)
    {
        AssetManager mngr = context.getAssets();

        hashMapFonts = new HashMap<AssetTypefaces, Typeface>();
        hashMapFonts.put(AssetTypefaces.RobotoLight, Typeface.createFromAsset(mngr, "fonts/Roboto-Light.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoThin, Typeface.createFromAsset(mngr, "fonts/Roboto-Thin.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedBold, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Bold.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedLight, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Light.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedRegular, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Regular.ttf"));
    }

    private Typeface getTypeface(String fontName)
    {
        try
        {
            AssetTypefaces typeface = AssetTypefaces.valueOf(fontName);
            return hashMapFonts.get(typeface);
        }
        catch (IllegalArgumentException e)
        {
            // e.printStackTrace();
            return Typeface.DEFAULT;
        }
    }

    public void setupLayoutTypefaces(View v)
    {
        try
        {
            if (v instanceof ViewGroup)
            {
                ViewGroup vg = (ViewGroup) v;
                for (int i = 0; i < vg.getChildCount(); i++)
                {
                    View child = vg.getChildAt(i);
                    setupLayoutTypefaces(child);
                }
            }
            else if (v instanceof TextView)
            {
                ((TextView) v).setTypeface(getTypeface(v.getTag().toString()));
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            // ignore
        }
    }
}

0

Trabajando para Xamarin.Android:

Clase:

public class FontsOverride
{
    public static void SetDefaultFont(Context context, string staticTypefaceFieldName, string fontAssetName)
    {
        Typeface regular = Typeface.CreateFromAsset(context.Assets, fontAssetName);
        ReplaceFont(staticTypefaceFieldName, regular);
    }

    protected static void ReplaceFont(string staticTypefaceFieldName, Typeface newTypeface)
    {
        try
        {
            Field staticField = ((Java.Lang.Object)(newTypeface)).Class.GetDeclaredField(staticTypefaceFieldName);
            staticField.Accessible = true;
            staticField.Set(null, newTypeface);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

Implementación de la aplicación:

namespace SomeAndroidApplication
{
    [Application]
    public class App : Application
    {
        public App()
        {

        }

        public App(IntPtr handle, JniHandleOwnership transfer)
            : base(handle, transfer)
        {

        }

        public override void OnCreate()
        {
            base.OnCreate();

            FontsOverride.SetDefaultFont(this, "MONOSPACE", "fonts/Roboto-Light.ttf");
        }
    }
}

Estilo:

<style name="Theme.Storehouse" parent="Theme.Sherlock">
    <item name="android:typeface">monospace</item>
</style>

0

Parece que el uso de fuentes personalizadas se ha simplificado con Android O, básicamente puedes usar xml para lograrlo. Adjunté un enlace a la documentación oficial de Android como referencia, y espero que esto ayude a las personas que aún necesitan esta solución. Trabajar con fuentes personalizadas en Android


0

Puede ser útil saber que a partir de Android 8.0 (API nivel 26) puede utilizar una fuente personalizada en XML .

En pocas palabras, puede hacerlo de la siguiente manera.

  1. Pon la fuente en la carpeta res/font.

  2. Úselo en el atributo de un widget

<Button android:fontFamily="@font/myfont"/>

o ponerlo en res/values/styles.xml

<style name="MyButton" parent="android:Widget.Button">
    <item name="android:fontFamily">@font/myfont</item>
</style>

y úsalo como estilo

<Button style="@style/MyButton"/>

0

Utilice el atributo "fontPath" directamente en el archivo xml.

para usar en style.xml

<item name = "fontPath"> fuentes / ProximaNovaSemibold.ttf </item>

para usar en archivo de diseño directo

fontPath = "fuentes / ProximaNovaBold.ttf"

(Nota: No es necesario utilizar el atributo de aplicación / android en el prefijo)


-6

Absolutamente posible. Muchas formas de hacerlo. La forma más rápida es crear una condición con el método try-catch. Pruebe su condición de estilo de fuente determinada, detecte el error y defina el otro estilo de fuente.


7
¿Puede proporcionar una demostración para demostrar su respuesta?
Mark
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.