Android之替换APP字体——Typeface
来源:互联网 发布:电脑软件技术培训 编辑:程序博客网 时间:2024/05/16 10:53
公司客户端开发分为IOS组、Android组与HTML5组,在字体统一上就出现了问题,需要Android采用IOS的字体,这样就只能替换APP字体了。现在才发现Android开发有时候就是很苦逼,特别是拥有IOS开发组的公司,因为不管在设计风格、逻辑、效果都要以IOS为准,其实大家上网搜索下就会发现许多Android的效果都是模仿IOS的(例如横向滑动删除),这种趋势让身为Android程序员情何以堪啊,让Google情何以堪啊。
回到主题,切换APP字体的思路一般都会想到自定义控件(TextView、EditView),但是线上的项目中得有多少这些控件啊,就算用Stuido替换工具来替换也会承担一些风险和资源的消耗,主要是这种思路太死板了,就考虑Android底层应该在字体设置上有放开的方法,然后可以通过Application对控件进行过滤与替换,通过一番搜索果然有所发现,下面贴出代码:
使用方法:
1、请在Application中添加以下代码替换全局字体FontUtils.getInstance().replaceSystemDefaultFontFromAsset(this, "fonts/xxx.ttf");2、请在设置主题代码中添加以下代码<item name="android:typeface">monospace</item>
package core.util;import android.app.Application;import android.content.Context;import android.graphics.Typeface;import android.support.annotation.NonNull;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.lang.ref.SoftReference;import java.lang.reflect.Field;import java.util.HashMap;import java.util.Map;public class FontUtils { private static final String TAG = FontUtils.class.getSimpleName(); private Map<String, SoftReference<Typeface>> mCache = new HashMap<>(); private static FontUtils sSingleton = null; public static Typeface DEFAULT = Typeface.DEFAULT; // disable instantiate private FontUtils() {} public static FontUtils getInstance() { // double check if (sSingleton == null) { synchronized(FontUtils.class) { if (sSingleton == null) { sSingleton = new FontUtils(); } } } return sSingleton; } /** * <p>Replace the font of specified view and it's children</p> * @param root The root view. * @param fontPath font file path relative to 'assets' directory. */ public void replaceFontFromAsset(@NonNull View root, @NonNull String fontPath) { replaceFont(root, createTypefaceFromAsset(root.getContext(), fontPath)); } /** * <p>Replace the font of specified view and it's children</p> * @param root The root view. * @param fontPath font file path relative to 'assets' directory. * @param style One of {@link Typeface#NORMAL}, {@link Typeface#BOLD}, {@link Typeface#ITALIC}, {@link Typeface#BOLD_ITALIC} */ public void replaceFontFromAsset(@NonNull View root, @NonNull String fontPath, int style) { replaceFont(root, createTypefaceFromAsset(root.getContext(), fontPath), style); } /** * <p>Replace the font of specified view and it's children</p> * @param root The root view. * @param fontPath The full path to the font data. */ public void replaceFontFromFile(@NonNull View root, @NonNull String fontPath) { replaceFont(root, createTypefaceFromFile(fontPath)); } /** * <p>Replace the font of specified view and it's children</p> * @param root The root view. * @param fontPath The full path to the font data. * @param style One of {@link Typeface#NORMAL}, {@link Typeface#BOLD}, {@link Typeface#ITALIC}, {@link Typeface#BOLD_ITALIC} */ public void replaceFontFromFile(@NonNull View root, @NonNull String fontPath, int style) { replaceFont(root, createTypefaceFromFile(fontPath), style); } /** * <p>Replace the font of specified view and it's children with specified typeface</p> */ private void replaceFont(@NonNull View root, @NonNull Typeface typeface) { if (root == null || typeface == null) { return; } if (root instanceof TextView) { // If view is TextView or it's subclass, replace it's font TextView textView = (TextView)root; // Extract previous style of TextView int style = Typeface.NORMAL; if (textView.getTypeface() != null) { style = textView.getTypeface().getStyle(); } textView.setTypeface(typeface, style); } else if (root instanceof ViewGroup) { // If view is ViewGroup, apply this method on it's child views ViewGroup viewGroup = (ViewGroup) root; for (int i = 0; i < viewGroup.getChildCount(); ++i) { replaceFont(viewGroup.getChildAt(i), typeface); } } // else return } /** * <p>Replace the font of specified view and it's children with specified typeface and text style</p> * @param style One of {@link Typeface#NORMAL}, {@link Typeface#BOLD}, {@link Typeface#ITALIC}, {@link Typeface#BOLD_ITALIC} */ private void replaceFont(@NonNull View root, @NonNull Typeface typeface, int style) { if (root == null || typeface == null) { return; } if (style < 0 || style > 3) { style = Typeface.NORMAL; } if (root instanceof TextView) { // If view is TextView or it's subclass, replace it's font TextView textView = (TextView)root; textView.setTypeface(typeface, style); } else if (root instanceof ViewGroup) { // If view is ViewGroup, apply this method on it's child views ViewGroup viewGroup = (ViewGroup) root; for (int i = 0; i < viewGroup.getChildCount(); ++i) { replaceFont(viewGroup.getChildAt(i), typeface, style); } } // else return } /** * <p>Create a Typeface instance with specified font file</p> * @param fontPath font file path relative to 'assets' directory. * @return Return created typeface instance. */ private Typeface createTypefaceFromAsset(Context context, String fontPath) { SoftReference<Typeface> typefaceRef = mCache.get(fontPath); Typeface typeface = null; if (typefaceRef == null || (typeface = typefaceRef.get()) == null) { typeface = Typeface.createFromAsset(context.getAssets(), fontPath); typefaceRef = new SoftReference<>(typeface); mCache.put(fontPath, typefaceRef); } return typeface; } private Typeface createTypefaceFromFile(String fontPath) { SoftReference<Typeface> typefaceRef = mCache.get(fontPath); Typeface typeface = null; if (typefaceRef == null || (typeface = typefaceRef.get()) == null) { typeface = Typeface.createFromFile(fontPath); typefaceRef = new SoftReference<>(typeface); mCache.put(fontPath, typefaceRef); } return typeface; } /** * <p>Replace system default font. <b>Note:</b>you should also add code below to your app theme in styles.xml. </p> * {@code <item name="android:typeface">monospace</item>} * <p>The best place to call this method is {@link Application#onCreate()}, it will affect * whole app font.If you call this method after view is visible, you need to invalid the view to make it effective.</p> * @param context {@link Context Context} * @param fontPath font file path relative to 'assets' directory. */ public void replaceSystemDefaultFontFromAsset(@NonNull Context context, @NonNull String fontPath) { replaceSystemDefaultFont(createTypefaceFromAsset(context, fontPath)); } /** * <p>Replace system default font. <b>Note:</b>you should also add code below to your app theme in styles.xml. </p> * {@code <item name="android:typeface">monospace</item>} * <p>The best place to call this method is {@link Application#onCreate()}, it will affect * whole app font.If you call this method after view is visible, you need to invalid the view to make it effective.</p> * @param context {@link Context Context} * @param fontPath The full path to the font data. */ public void replaceSystemDefaultFontFromFile(@NonNull Context context, @NonNull String fontPath) { replaceSystemDefaultFont(createTypefaceFromFile(fontPath)); } /** * <p>Replace system default font. <b>Note:</b>you should also add code below to your app theme in styles.xml. </p> * {@code <item name="android:typeface">monospace</item>} * <p>The best place to call this method is {@link Application#onCreate()}, it will affect * whole app font.If you call this method after view is visible, you need to invalid the view to make it effective.</p> */ private void replaceSystemDefaultFont(@NonNull Typeface typeface) { modifyObjectField(null, "MONOSPACE", typeface); } private void modifyObjectField(Object obj, String fieldName, Object value) { try { Field defaultField = Typeface.class.getDeclaredField(fieldName); defaultField.setAccessible(true); defaultField.set(obj, value); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }}
核心代码在:replaceFont方法,替换TextView的字体,那大家就会疑问了,这个工具类只替换了Textview的字体,那如果用了EditView、RadioButton等呢。大家可以看下那些控件的父类,它们都是继承TextView,这样就豁然开朗,细节果然决定成败啊。整个工具类在字体替换的效率上都有所体现,采用软引用和HashMap缓存策略大大降低替换时的资源消耗,考虑的确很全面,并采用反射机制对Typeface进行设置达到换字体的目的。
这个工具类几乎完美,的确有许多值得学习的地方,比如在单例设置是采用了synchronized 摒弃了懒汉的模式,在资源使用上用到了SoftReference 软引用,在缓存上用了HashMap,最后采用反射赋值,这几点都是可圈可点。如果将缓存的HashMap换成ConcurrentHashMap或许在多线程环境下性能表现会更好些。
下面是该工具类作者的GitHub:https://github.com/whinc
0 0
- Android之替换APP字体——Typeface
- Android改变字体方法——Typeface
- Android系统工具之typeface字体设置
- text——android.graphic.typeface字体类
- Android 替换app字体
- Android字体Typeface设置
- Android字体Typeface设置
- Android字体Typeface设置
- android 字体TypeFace设置.
- 杂乱之android的字体相关类Typeface
- Android studio设置字体格式之Typeface(字型)
- 杂乱之android的字体相关类Typeface
- android 自定义字体 typeface设置
- Android 字体设置-Typeface讲解
- Android 字体设置-Typeface讲解
- Android 字体设置 Typeface 设置
- Android 控件设置字体【Typeface】
- Android中的字体设置-Typeface
- java中获取相对当前日的任何任意一天的方法
- SAP中添加自定义菜单
- Fragment中menu菜单注意事项
- iOS 平台UI设计小结
- android 的Menu菜单
- Android之替换APP字体——Typeface
- iOS崩溃调试的使用和技巧总结
- java之单例模式【整理】
- GNU gcc 和 g++ 的区别详解
- 多线程初探(七)
- 屏幕截图ScreenShot方法总结
- 史上最详细的Android Studio系列教程(一)--下载和安装
- PHP ( $_SERVER[" ... "]的用法)
- 静态资源较多的站点使用nginx与apache的负载均衡架构