Использование пользовательского шрифта в Android
Я хочу использовать пользовательский шрифт для моего приложения для android, которое я создаю.
Я могу индивидуально изменить шрифт каждого объекта из кода, но у меня их сотни.
и
- есть ли способ сделать это из XML? [Установка пользовательского шрифта]
- есть ли способ сделать это из кода в одном месте, чтобы сказать, что все приложения и все компоненты должны использовать пользовательский шрифт вместо стандартного один?
19 ответов:
есть ли способ сделать это из XML?
нет, к сожалению. Вы можете указать только встроенные шрифты через XML.есть ли способ сделать это из кода одно место, чтобы сказать, что весь применение и все компоненты вместо этого следует использовать пользовательский шрифт по умолчанию?
Не то, что я знаю.есть множество вариантов для этих в настоящее время:
ресурсы шрифтов и backports в Android SDK, если вы используете
appcompatсторонние библиотеки для тех, кто не используя
appcompat, хотя не все будут поддерживать определение шрифта в ресурсах макета
Да, это возможно.
вы должны создать пользовательский вид, который простирается вид текста.
на
attrs.xmlна :<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>на
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>на
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); } }
Я сделал это более "грубой силой", которая не требует изменений в XML-макете или действиях.
протестировано на Android версии 2.1 - 4.4. Запустите это при запуске приложения, в вашем классе приложений:
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); } }более полный пример см. В разделе http://github.com/perchrh/FontOverrideExample
хотя я поддерживаю ответ Маниша как самый быстрый и целевой метод, я также видел наивные решения, которые просто рекурсивно повторяют иерархию представлений и обновляют шрифты всех элементов по очереди. Что-то вроде этого:
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 } }вам нужно будет вызвать эту функцию на ваших представлениях как после раздувания макета, так и в вашей активности
onContentChanged()методы.
я смог сделать это централизованно, вот результат:
у меня есть следующие
Activityи я расширяюсь от него, если мне нужны пользовательские шрифты: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")); } }но если я использую упражнение из пакета поддержки, например,
FragmentActivityтогда я использую это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")); } }Я не тестировал этот код с
Fragments еще, но надеюсь, что это сработает.мой
FontUtilsпросто, что также решает упомянутую проблему pre-ICS здесь 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 разных шрифта в моем приложении для разных widgeds! Я использую этот способ:
в моем классе приложений я создаю статический метод:
public static Typeface getTypeface(Context context, String typeface) { if (mFont == null) { mFont = Typeface.createFromAsset(context.getAssets(), typeface); } return mFont; }строковый шрифт представляет собой xyz.ttf в папке активов. (я создал класс констант) Теперь вы можете использовать это везде в вашем приложении:
mTextView = (TextView) findViewById(R.id.text_view); mTextView.setTypeface(MyApplication.getTypeface(this, Constants.TYPEFACE_XY));единственная проблема, вам нужно это для каждого виджета, где вы хотите использовать шрифт! Но я думаю, что это лучший способ.
используя pospi это предложение и работа со свойством 'tag', как Ричард сделал, я создал пользовательский класс, который загружает пользовательские шрифты и применяет их взгляды по их тегам.
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 } } }в вашей деятельности или фрагмент, вы просто называете
Fonts fonts = new Fonts(getActivity()); fonts.setupLayoutTypefaces(mainLayout);
Я нашел хорошее решение на блог Лизы Рей. С помощью новой привязки данных можно установить шрифт в ваших XML-файлах.
@BindingAdapter({"bind:font"}) public static void setFont(TextView textView, String fontName){ textView.setTypeface(Typeface.createFromAsset(textView.getContext().getAssets(), "fonts/" + fontName)); }в XML:
<TextView app:font="@{`Source-Sans-Pro-Regular.ttf`}" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
Я думаю, что может быть более удобный способ сделать это. Следующий класс установит пользовательский тип лица для всех ваших компонентов вашего приложения (с настройкой для каждого класса).
/** * 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; } } }
реализации LayoutInflater по умолчанию не поддерживают указание шрифта шрифта из xml. Однако я видел, как это делается в xml, предоставляя пользовательскую фабрику для LayoutInflater, которая будет анализировать такие атрибуты из тега xml.
основная структура хотела бы этого.
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()); } }в этой статье предоставляет более подробное объяснение этих механизмов и как автор пытается обеспечить поддержку xml-макета для шрифтов в этом путь. Код для реализации автора можно найти здесь.
установка пользовательского шрифта в обычный ProgressDialog/AlertDialog:
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);
Да, это возможно путем переопределения шрифта по умолчанию. Я последовал этой решение и он работал как шарм для всех TextViews и ActionBar текста тоже с одним изменением.
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 } }стили.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>вместо темы.xml как упоминалось в приведенной выше ссылке, я упомянул шрифт по умолчанию для переопределения в моих стилях.xml в моем теге темы приложения по умолчанию. Шрифты по умолчанию, которые могут быть перезаписаны несколько засечками, без засечек, моноширинный и нормальный.
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); } } }Первоначально я не знал, что шрифты, которые будут перезаписаны, фиксированы и заданы определенные значения, но в конечном итоге это помогло мне понять, как Android работает со шрифтами и шрифтами и их значениями по умолчанию, что является другой точкой зрения.
Я не знаю, изменяет ли он все приложение, но мне удалось изменить некоторые компоненты, которые иначе не могли быть изменены, сделав это:
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);
мне нравится предложение поспи. Почему бы не использовать свойство 'tag' представления (которое вы можете указать в XML - 'android: tag'), чтобы указать любой дополнительный стиль, который вы не можете сделать в XML. Мне нравится JSON, поэтому я бы использовал строку JSON для указания набора ключей/значений. Этот класс делает свою работу-просто позвоните
Style.setContentView(this, [resource id])в вашей деятельности.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))); } }очевидно, что вы хотите обрабатывать больше, чем просто шрифт, чтобы сделать использование JSON стоящим.
преимуществом свойства ' tag ' является что вы можете установить его на базовый стиль, который вы используете в качестве темы и, таким образом, он применяется ко всем вашим представлениям автоматически. EDIT: это приводит к катастрофе во время инфляции на Android 4.0.3. Вы все еще можете использовать стиль и применять его к текстовым представлениям по отдельности.
одна вещь, которую вы увидите в коде - в некоторых представлениях есть тег без явного набора - странно, что это строка "Αποκοπή" - которая "вырезана" на греческом языке, согласно google translate! Что ад...?
ответ @ majinboo пересмотрен для управления производительностью и памятью. Любое более чем одно действие, связанное с необходимостью шрифта, может использовать этот класс шрифта, предоставляя сам конструктор в качестве параметра.
@Override public void onCreate(Bundle savedInstanceState) { Font font = new Font(this); }пересмотренный класс шрифтов, как показано ниже:
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 } } }
Работает на Xamarin.Android:
класс:
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); } } }Приложения:
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"); } } }стиль:
<style name="Theme.Storehouse" parent="Theme.Sherlock"> <item name="android:typeface">monospace</item> </style>
похоже, что использование пользовательских шрифтов было легко с Android O, вы можете в основном использовать xml для достижения этой цели. Я прикрепил ссылку на официальную документацию Android Для справки, и, надеюсь, это поможет людям, которым все еще нужно это решение. работа с пользовательскими шрифтами в Android
новая библиотека поддержки 26 теперь позволяет использовать шрифты в XML.
вот как это шрифты в XML
абсолютно возможно. Много способов сделать это. Самый быстрый способ, создать условие с помощью метода try-catch.. попробуйте свое определенное условие стиля шрифта, поймайте ошибку и определите другой стиль шрифта.

Comments