Использовать шрифт Roboto для более ранних устройств

Я хотел бы использовать шрифт Roboto в своем приложении для Android и убедиться, что он работает для более ранних версий Android, у которых нет установленного шрифта. Я знаю, что могу сделать это, используя Typeface.createFromAsset (), а затем вручную установив шрифт для каждого из моих TextViews / Buttons / Other-Objects. Это кажется большой болью для этого для каждого объекта, который я показываю на экране.

Мой вопрос: есть ли лучший способ сделать это? Какой-то вспомогательный класс или способ установить пользовательский шрифт в файле темы .xml? Любое автоматическое будет лучше, чем вручную перечислять каждый объект на каждом экране и изменять шрифт.

Благодаря!

Solutions Collecting From Web of "Использовать шрифт Roboto для более ранних устройств"

Извлеките все виды изнутри, проверьте его тип и примените соответствующие действия.

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

Выше принятый ответ правильный, но я просто хотел реализовать свою реализацию здесь

Мой класс утилиты:

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

Как использовать его, считая this Activity:

 AndroidUtils.setRobotoFont(this, view); 

Чтобы установить тот же шрифт для всего TextView, вы можете использовать decorView своей деятельности:

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

Если у вас есть адаптеры или фрагменты, не забудьте также установить их шрифт.

Смотрите также.

Благодаря @Jitsu, @Arnaud и @Pawan M, я сделал свое решение, лучше всех из них:

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

И последнее в вашей основной деятельности onCreate:

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

И в моих списках с пользовательскими представлениями код выше не работал, поэтому мне пришлось сделать следующее:

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

Вот моя улучшенная версия этого решения. Он может кэшировать шрифты и принимать во внимание параметры параметра TextView.textStyle. Таким образом, он может выделять жирный текст. http://anton.averin.pro/2012/09/12/how-to-use-android-roboto-font-in-honeycomb-and-earlier-versions/

Я использую другое решение. Я задал для параметра custom LayoutInflater.Factory . Поэтому у меня есть полный доступ к просмотру после его создания. Я могу установить пользовательский шрифт для каждого TextView без итерации по иерархии представлений. Одна вещь, которую вы должны сделать, чтобы использовать пользовательский шрифт во всем своем приложении, – это вызвать new Font(...).install() в вашей базовой активности. См. Приведенный ниже пример.

Вот мое решение с образцом использования:

 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 (danikula@gmail.com) */ 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; } } } 

Обратите внимание, что он имеет зависимость от guava , но вы можете реализовать эти методы самостоятельно.

Лучше всего разрешить каллиграфию