Usar fuente Roboto para dispositivos anteriores

Me gustaría usar la fuente Roboto en mi aplicación de Android y asegurarse de que funciona para las versiones anteriores de Android que no tienen la fuente instalada. Sé que puedo hacer esto usando Typeface.createFromAsset () y fijar manualmente la fuente para cada uno de mis TextViews / Buttons / Other-Objects. Parece un gran dolor para hacer esto por cada objeto que muestro en la pantalla sin embargo.

Mi pregunta es, ¿hay una mejor manera de hacer esto? Alguna clase de ayuda o una forma de establecer una fuente personalizada en un archivo de tema .xml? Cualquier cosa automatizada sería mejor que enumerar manualmente cada objeto en cada pantalla y cambiar la fuente.

¡Gracias!

Recupere todas las vistas dentro de la actividad, compruebe su tipo y aplique la acción apropiada.

Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Roboto/Roboto-Regular.ttf"); for (View view : allViews) { if (view instanceof TextView) { TextView textView = (TextView) view; textView.setTypeface(typeface); } } 

La respuesta aceptada es correcta pero solo quería proporcionar mi implementación aquí

Mi clase de utilidad:

 package com.example.utils; import android.content.Context; import android.graphics.Typeface; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class AndroidUtils { private static Typeface robotoTypeFace; public static void setRobotoFont (Context context, View view) { if (robotoTypeFace == null) { robotoTypeFace = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto/Roboto-Regular.ttf"); } setFont(view, robotoTypeFace); } private static void setFont (View view, Typeface robotoTypeFace) { if (view instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup)view).getChildCount(); i++) { setFont(((ViewGroup)view).getChildAt(i), robotoTypeFace); } } else if (view instanceof TextView) { ((TextView) view).setTypeface(robotoTypeFace); } } } 

Cómo usarlo, suponiendo que se trata de una Actividad:

 AndroidUtils.setRobotoFont(this, view); 

Para establecer la misma fuente en todos los TextView puede utilizar el decorView de su actividad:

 ViewGroup godfatherView = (ViewGroup)this.getWindow().getDecorView(); AndroidUtils.setRobotoFont(this, godfatherView); 

Si tiene adaptadores o fragmentos, no olvide establecer su fuente también.

Vea aquí también.

Gracias a @Jitsu, @Arnaud y @Pawan M, hice mi solución, mejor que todos ellos solos:

 /** * Adapted from http://stackoverflow.com/a/12387343/450148 * * @author Anton Averin * @author Felipe Micaroni Lalli */ package net.alouw.alouwCheckin.util; import android.content.Context; import android.graphics.Typeface; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.EnumMap; import java.util.Map; public final class FontUtils { private FontUtils() { } private enum FontType { BOLD("fonts/Roboto/Roboto-BoldCondensed.ttf"), BOLD_ITALIC("fonts/Roboto/Roboto-BoldCondensedItalic.ttf"), NORMAL("fonts/Roboto/Roboto-Condensed.ttf"), ITALIC("fonts/Roboto/Roboto-CondensedItalic.ttf"); private final String path; FontType(String path) { this.path = path; } public String getPath() { return path; } } /* cache for loaded Roboto typefaces*/ private static Map<FontType, Typeface> typefaceCache = new EnumMap<FontType, Typeface>(FontType.class); /** * Creates Roboto typeface and puts it into cache */ private static Typeface getRobotoTypeface(Context context, FontType fontType) { String fontPath = fontType.getPath(); if (!typefaceCache.containsKey(fontType)) { typefaceCache.put(fontType, Typeface.createFromAsset(context.getAssets(), fontPath)); } return typefaceCache.get(fontType); } /** * Gets roboto typeface according to passed typeface style settings. * <p/> * Will get Roboto-Bold for Typeface.BOLD etc */ private static Typeface getRobotoTypeface(Context context, Typeface originalTypeface) { FontType robotoFontType = null; if (originalTypeface == null) { robotoFontType = FontType.NORMAL; } else { int style = originalTypeface.getStyle(); switch (style) { case Typeface.BOLD: robotoFontType = FontType.BOLD; break; case Typeface.BOLD_ITALIC: robotoFontType = FontType.BOLD_ITALIC; break; case Typeface.ITALIC: robotoFontType = FontType.ITALIC; break; case Typeface.NORMAL: robotoFontType = FontType.NORMAL; break; } } return (robotoFontType == null) ? originalTypeface : getRobotoTypeface(context, robotoFontType); } /** * Walks ViewGroups, finds TextViews and applies Typefaces taking styling in consideration * * @param context - to reach assets * @param view - root view to apply typeface to */ public static void setRobotoFont(Context context, View view) { if (view instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { setRobotoFont(context, ((ViewGroup) view).getChildAt(i)); } } else if (view instanceof TextView) { Typeface currentTypeface = ((TextView) view).getTypeface(); ((TextView) view).setTypeface(getRobotoTypeface(context, currentTypeface)); } } } 

Y lo último en su actividad principal onCreate:

 if (Build.VERSION.SDK_INT < 11) { ViewGroup godfatherView = (ViewGroup) this.getWindow().getDecorView(); FontUtils.setRobotoFont(this, godfatherView); } 

Y en mis listas con vistas personalizadas el código anterior no funcionó, así que tuve que hacer esto:

 @Override public View getView(int position, View convertView, ViewGroup parent) { // (...) View view = // build your custom view here if (Build.VERSION.SDK_INT < 11) { FontUtils.setRobotoFont(activity, view); } return view; } 

Esta es mi versión mejorada de esta solución. Puede almacenar las fuentes en caché y toma en consideración la configuración de los parámetros TextView.textStyle. Por lo tanto, puede establecer texto en negrita. http://anton.averin.pro/2012/09/12/how-to-use-android-roboto-font-in-honeycomb-and-earlier-versions/

Utilizo otra solución. Establecer LayoutInflater.Factory personalizado a la actividad. Así que tengo acceso completo a la vista después de la creación. Puedo instalar la fuente de encargo para cada TextView sin iterar en jerarquía de la visión. Una cosa que usted debe hacer para usar la fuente personalizada en toda su aplicación es llamar new Font(...).install() en su actividad base. Vea la ilustración a continuación.

Aquí está mi solución con muestra de uso:

 import java.util.Map; import com.google.common.collect.Maps; import static com.google.common.base.Preconditions.checkNotNull; import android.R; import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Typeface; import android.support.v4.app.FragmentActivity; import android.util.AttributeSet; import android.util.Log; import android.view.InflateException; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; /** * Provides an ability to apply custom font to all {@link TextView} and subclasses. * * To install custom font use method {@link #install(Activity)} in {@link Activity#onCreate(android.os.Bundle)} * <b>before</b> calling super.onCreate(Bundle). * * <p/>Example of usage: * <pre> * {@code * public class BaseActivity extends SherlockFragmentActivity { * * protected void onCreate(Bundle state) { * applyCustomFontForPreICS(); * super.onCreate(state); * } * * private void applyCustomFontForPreICS() { * boolean isPreICS = Build.VERSION.SDK_INT < BUILD_VERSION_CODE_ICE_CREAM_SANDWICH * if (isPreICS) { * new Font( * "font/roboto_regular.ttf", * "font/roboto_bold.ttf", * "font/roboto_italic.ttf", * "font/roboto_bold_italic.ttf" * ).install(this); * } * } * } * } * </pre> * * @author Alexey Danilov ([email protected]) */ public class Font { private static final Map<String, Typeface> FONTS = Maps.newHashMap(); private String regularFontPath; private String boldFontPath; private String italicFontPath; private String boldItalicFontPath; /** * Creates instance to be used for setting particular font. * * @param regularPath regular font assets path, must be not {@code null} * @param boldPath bold font assets path, must be not {@code null} * @param italicPath italic font assets path, must be not {@code null} * @param boldItalicPath bold and italic font assets path, must be not {@code null} */ public Font(String regularPath, String boldPath, String italicPath, String boldItalicPath) { this.regularFontPath = checkNotNull(regularPath); this.boldFontPath = checkNotNull(boldPath); this.italicFontPath = checkNotNull(italicPath); this.boldItalicFontPath = checkNotNull(boldItalicPath); } /** * Installs custom font to activity. * * @param activity an activity custom font will be installed to, must be not {@code null}. */ public void install(Activity activity) { checkNotNull(activity, "Activity must be not null!"); LayoutInflater layoutInflater = activity.getLayoutInflater(); boolean factoryIsEmpty = layoutInflater.getFactory() == null; if (!factoryIsEmpty) { throw new IllegalStateException("Impossible to use this method for this activity: layout factory is set!"); } layoutInflater.setFactory(new FontLayoutInflaterFactory()); } private Typeface getFont(int type, Context context) { switch (type) { case Typeface.NORMAL: return getFont(context, regularFontPath); case Typeface.BOLD: return getFont(context, boldFontPath); case Typeface.ITALIC: return getFont(context, italicFontPath); case Typeface.BOLD_ITALIC: return getFont(context, boldItalicFontPath); default: { throw new IllegalArgumentException("Undefined font type " + type); } } } private Typeface getFont(Context context, String path) { if (FONTS.containsKey(path)) { return FONTS.get(path); } else { Typeface typeface = makeTypeface(context, path); FONTS.put(path, typeface); return typeface; } } private Typeface makeTypeface(Context context, String path) { try { return Typeface.createFromAsset(context.getAssets(), path); } catch (Exception e) { // add user-friendly error message throw new IllegalArgumentException(String.format("Error creating font from assets path '%s'", path), e); } } private void applyFontToTextView(Context context, TextView textView, AttributeSet attrs) { int[] fontStyleAttributes = {R.attr.textStyle}; TypedArray typedArray = context.obtainStyledAttributes(attrs, fontStyleAttributes); boolean isStyleSpecified = typedArray.getIndexCount() != 0; int type = isStyleSpecified ? typedArray.getInt(0, Typeface.NORMAL) : Typeface.NORMAL; Typeface font = getFont(type, context); textView.setTypeface(font, type); } private final class FontLayoutInflaterFactory implements LayoutInflater.Factory { // to improve perfomance the package with the most usable components should be the first. private final String[] ANDROID_UI_COMPONENT_PACKAGES = { "android.widget.", "android.webkit.", "android.view." }; @Override public View onCreateView(String name, Context context, AttributeSet attrs) { try { // we install custom LayoutInflater.Factory, so FragmentActivity have no chance set own factory and // inflate tag <fragment> in method onCreateView. So call it explicitly. if ("fragment".equals(name) && context instanceof FragmentActivity) { FragmentActivity fragmentActivity = (FragmentActivity) context; return fragmentActivity.onCreateView(name, context, attrs); } View view = createView(name, attrs, LayoutInflater.from(context)); if (view == null) { // It's strange! The view is not ours neither android's. May be the package of this view // is not listed in ANDROID_UI_COMPONENT_PACKAGES. Return null for the default behavior. Log.d(LOG_TAG, "Cannot create view with name: " + name); return null; } if (view instanceof TextView) { TextView textView = (TextView) view; applyFontToTextView(context, textView, attrs); } return view; } catch (InflateException e) { Log.e(LOG_TAG, "Error inflating view", e); return null; } catch (ClassNotFoundException e) { Log.e(LOG_TAG, "Error inflating view", e); return null; } } private View createView(String name, AttributeSet attrs, LayoutInflater layoutInflater) throws ClassNotFoundException { View view = null; boolean isAndroidComponent = name.indexOf('.') == -1; if (isAndroidComponent) { // We don't know package name of the view with the given simple name. Try android ui packages listed in // ANDROID_UI_COMPONENT_PACKAGES // The same implementation is in the class PhoneLayoutInflater from internal API for (String androidPackage : ANDROID_UI_COMPONENT_PACKAGES) { try { view = layoutInflater.createView(name, androidPackage, attrs); if (view != null) { break; } } catch (ClassNotFoundException e) { // Do nothing, we will try another package } } } else { view = layoutInflater.createView(name, null, attrs); } return view; } } } 

Tenga en cuenta que tiene dependencia de la guayaba , pero puede implementar este método por sí mismo.

El mejor sollution nunca es caligrafía

  • ¿Por qué android le da advertencia sobre el uso de tamaño menor que 12sp?
  • Android: ¿Cómo obtener una vista dada una actividad dentro de una clase normal?
  • Android Shape - Gradiente debe ir al lado derecho
  • Comportamiento extraño al usar WebView y RelativeLayout en pantalla completa
  • Listview - Pie de página en la parte inferior de la pantalla
  • Listado de listas de anuncios de Android y sección Mes y lista de fechas
  • Limitar el tamaño de la vista de texto horizontalmente
  • ¿Cómo establecer el ancho y la altura para la vista personalizada en forma programática?
  • Cómo crear barra de progreso como la imagen en Android
  • Establecer parámetros de diseño dinámicamente
  • Cambiar el título del encabezado de NavigationView
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.