• Android替换APP字体 — Typeface


    Android替换APP字体 — Typeface

      APP字体的思路一般都会想到自定义控件(TextView、EditView),但是项目中会有很多种控件,就算用也会承担一些风险和资源的消耗,主要是这种思路太死板了,就考虑Android底层应该在字体设置上有放开的方法,然后可以通过Application对控件进行过滤与替换,通过一番搜索果然有所发现,下面贴出代码:

      1、请在Application中添加以下代码替换全局字体

    // 字体放在 assets 文件夹下
    FontUtils.getInstance().replaceSystemDefaultFontFromAsset(this, "fonts/xxx.ttf"); // .otf 字体文件也可

      2、请在设置主题代码中添加以下代码

      主题代码为 application 中的theme属性的 style 里面。

    <item name="android:typeface">monospace</item>

      3、新建文件FontUtils.java

      1 package com.test.bean;
      2 import java.lang.ref.SoftReference;
      3 import java.lang.reflect.Field;
      4 import java.util.HashMap;
      5 import java.util.Map;
      6 
      7 import android.app.Application;
      8 import android.content.Context;
      9 import android.graphics.Typeface;
     10 import android.view.View;
     11 import android.view.ViewGroup;
     12 import android.widget.TextView;
     13 
     14 public class FontUtils {
     15     
     16     private Map<String, SoftReference<Typeface>> mCache = new HashMap<String, SoftReference<Typeface>>();
     17     private static FontUtils sSingleton = null;
     18 
     19     public static Typeface DEFAULT = Typeface.DEFAULT;
     20 
     21     // disable instantiate
     22     private FontUtils() {}
     23 
     24     public static FontUtils getInstance() {
     25         // double check
     26         if (sSingleton == null) {
     27             synchronized(FontUtils.class) {
     28                 if (sSingleton == null) {
     29                     sSingleton = new FontUtils();
     30                 }
     31             }
     32         }
     33         return sSingleton;
     34     }
     35 
     36     /**
     37      * <p>Replace the font of specified view and it's children</p>
     38      * @param root The root view.
     39      * @param fontPath font file path relative to 'assets' directory.
     40      */
     41     public void replaceFontFromAsset(View root, String fontPath) {
     42         replaceFont(root, createTypefaceFromAsset(root.getContext(), fontPath));
     43     }
     44 
     45     /**
     46      * <p>Replace the font of specified view and it's children</p>
     47      * @param root The root view.
     48      * @param fontPath font file path relative to 'assets' directory.
     49      * @param style One of {@link Typeface#NORMAL}, {@link Typeface#BOLD}, {@link Typeface#ITALIC}, {@link Typeface#BOLD_ITALIC}
     50      */
     51     public void replaceFontFromAsset(View root, String fontPath, int style) {
     52         replaceFont(root, createTypefaceFromAsset(root.getContext(), fontPath), style);
     53     }
     54 
     55     /**
     56      * <p>Replace the font of specified view and it's children</p>
     57      * @param root The root view.
     58      * @param fontPath The full path to the font data.
     59      */
     60     public void replaceFontFromFile(View root, String fontPath) {
     61         replaceFont(root, createTypefaceFromFile(fontPath));
     62     }
     63 
     64     /**
     65      * <p>Replace the font of specified view and it's children</p>
     66      * @param root The root view.
     67      * @param fontPath The full path to the font data.
     68      * @param style One of {@link Typeface#NORMAL}, {@link Typeface#BOLD}, {@link Typeface#ITALIC}, {@link Typeface#BOLD_ITALIC}
     69      */
     70     public void replaceFontFromFile(View root, String fontPath, int style) {
     71         replaceFont(root, createTypefaceFromFile(fontPath), style);
     72     }
     73 
     74     /**
     75      * <p>Replace the font of specified view and it's children with specified typeface</p>
     76      */
     77     private void replaceFont(View root, Typeface typeface) {
     78         if (root == null || typeface == null) {
     79             return;
     80         }
     81 
     82         if (root instanceof TextView) { // If view is TextView or it's subclass, replace it's font
     83             TextView textView = (TextView)root;
     84             // Extract previous style of TextView
     85             int style = Typeface.NORMAL;
     86             if (textView.getTypeface() != null) {
     87                 style = textView.getTypeface().getStyle();
     88             }
     89             textView.setTypeface(typeface, style);
     90         } else if (root instanceof ViewGroup) { // If view is ViewGroup, apply this method on it's child views
     91             ViewGroup viewGroup = (ViewGroup) root;
     92             for (int i = 0; i < viewGroup.getChildCount(); ++i) {
     93                 replaceFont(viewGroup.getChildAt(i), typeface);
     94             }
     95         } // else return
     96     }
     97 
     98     /**
     99      * <p>Replace the font of specified view and it's children with specified typeface and text style</p>
    100      * @param style One of {@link Typeface#NORMAL}, {@link Typeface#BOLD}, {@link Typeface#ITALIC}, {@link Typeface#BOLD_ITALIC}
    101      */
    102     private void replaceFont(View root, Typeface typeface, int style) {
    103         if (root == null || typeface == null) {
    104             return;
    105         }
    106         if (style < 0 || style > 3) {
    107             style = Typeface.NORMAL;
    108         }
    109 
    110         if (root instanceof TextView) { // If view is TextView or it's subclass, replace it's font
    111             TextView textView = (TextView)root;
    112             textView.setTypeface(typeface, style);
    113         } else if (root instanceof ViewGroup) { // If view is ViewGroup, apply this method on it's child views
    114             ViewGroup viewGroup = (ViewGroup) root;
    115             for (int i = 0; i < viewGroup.getChildCount(); ++i) {
    116                 replaceFont(viewGroup.getChildAt(i), typeface, style);
    117             }
    118         } // else return
    119     }
    120 
    121     /**
    122      * <p>Create a Typeface instance with specified font file</p>
    123      * @param fontPath font file path relative to 'assets' directory.
    124      * @return Return created typeface instance.
    125      */
    126     private Typeface createTypefaceFromAsset(Context context, String fontPath) {
    127         SoftReference<Typeface> typefaceRef = mCache.get(fontPath);
    128         Typeface typeface = null;
    129         if (typefaceRef == null || (typeface = typefaceRef.get()) == null) {
    130             typeface = Typeface.createFromAsset(context.getAssets(), fontPath);
    131             typefaceRef = new SoftReference<Typeface>(typeface);
    132             mCache.put(fontPath, typefaceRef);
    133         }
    134         return typeface;
    135     }
    136 
    137     private Typeface createTypefaceFromFile(String fontPath) {
    138         SoftReference<Typeface> typefaceRef = mCache.get(fontPath);
    139         Typeface typeface = null;
    140         if (typefaceRef == null || (typeface = typefaceRef.get()) == null) {
    141             typeface = Typeface.createFromFile(fontPath);
    142             typefaceRef = new SoftReference<Typeface>(typeface);
    143             mCache.put(fontPath, typefaceRef);
    144         }
    145         return typeface;
    146     }
    147 
    148     /**
    149      * <p>Replace system default font. <b>Note:</b>you should also add code below to your app theme in styles.xml. </p>
    150      * {@code <item name="android:typeface">monospace</item>}
    151      * <p>The best place to call this method is {@link Application#onCreate()}, it will affect
    152      * whole app font.If you call this method after view is visible, you need to invalid the view to make it effective.</p>
    153      * @param context {@link Context Context}
    154      * @param fontPath font file path relative to 'assets' directory.
    155      */
    156     public void replaceSystemDefaultFontFromAsset(Context context, String fontPath) {
    157         replaceSystemDefaultFont(createTypefaceFromAsset(context, fontPath));
    158     }
    159 
    160     /**
    161      * <p>Replace system default font. <b>Note:</b>you should also add code below to your app theme in styles.xml. </p>
    162      * {@code <item name="android:typeface">monospace</item>}
    163      * <p>The best place to call this method is {@link Application#onCreate()}, it will affect
    164      * whole app font.If you call this method after view is visible, you need to invalid the view to make it effective.</p>
    165      * @param context {@link Context Context}
    166      * @param fontPath The full path to the font data.
    167      */
    168     public void replaceSystemDefaultFontFromFile(Context context, String fontPath) {
    169         replaceSystemDefaultFont(createTypefaceFromFile(fontPath));
    170     }
    171 
    172     /**
    173      * <p>Replace system default font. <b>Note:</b>you should also add code below to your app theme in styles.xml. </p>
    174      * {@code <item name="android:typeface">monospace</item>}
    175      * <p>The best place to call this method is {@link Application#onCreate()}, it will affect
    176      * whole app font.If you call this method after view is visible, you need to invalid the view to make it effective.</p>
    177      */
    178     private void replaceSystemDefaultFont(Typeface typeface) {
    179         modifyObjectField(null, "MONOSPACE", typeface);
    180     }
    181 
    182     private void modifyObjectField(Object obj, String fieldName, Object value) {
    183         try {
    184             Field defaultField = Typeface.class.getDeclaredField(fieldName);
    185             defaultField.setAccessible(true);
    186             defaultField.set(obj, value);
    187 
    188         } catch (NoSuchFieldException e) {
    189             e.printStackTrace();
    190         } catch (IllegalAccessException e) {
    191             e.printStackTrace();
    192         }
    193     }
    194 }

      核心代码在:replaceFont方法,替换TextView的字体,那大家就会疑问了,这个工具类只替换了Textview的字体,那如果用了EditView、RadioButton等呢。大家可以看下那些控件的父类,它们都是继承TextView,这样就豁然开朗,细节果然决定成败啊。整个工具类在字体替换的效率上都有所体现,采用软引用和HashMap缓存策略大大降低替换时的资源消耗,考虑的确很全面,并采用反射机制对Typeface进行设置达到换字体的目的。

      这个工具类的确有许多值得学习的地方,比如在单例设置是采用了synchronized 摒弃了懒汉的模式,在资源使用上用到了SoftReference  软引用,在缓存上用了HashMap,最后采用反射赋值,这几点都是可圈可点。如果将缓存的HashMap换成ConcurrentHashMap或许在多线程环境下性能表现会更好些。

  • 相关阅读:
    sqlserver如何查询一个表的主键都是哪些表的外键
    sql server nullif的使用技巧,除数为零的处理技巧
    如何解决数据库中,数字+null=null
    sql server truncate table 删除表数据限制条件
    eclipse需要的环境变量就两个,一个是java_home指向JDK。另一个是Tomcat,自己去preference-sever下new一个
    解释Eclipse下Tomcat项目部署路径问题(.metadata.pluginsorg.eclipse.wst.server.core mp0wtpwebapps)
    mysql登录退出命令
    代码svn下载到本地后,关于数据库问题
    MySQL配置文件详解
    mysql查看存储过程show procedure status;
  • 原文地址:https://www.cnblogs.com/steffen/p/5854063.html
Copyright © 2020-2023  润新知