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
package com.test.bean;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map; import android.app.Application;
import android.content.Context;
import android.graphics.Typeface;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; public class FontUtils { private Map<String, SoftReference<Typeface>> mCache = new HashMap<String, SoftReference<Typeface>>();
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(View root, 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(View root, 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(View root, 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(View root, 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(View root, 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 = ; 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(View root, Typeface typeface, int style) {
if (root == null || typeface == null) {
return;
}
if (style < || style > ) {
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 = ; 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>(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>(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(Context context, 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(Context context, 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(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或许在多线程环境下性能表现会更好些。
Android替换APP字体 — Typeface的更多相关文章
- Android: 设置 app 字体大小不跟随系统字体调整而变化
在做 app 内字体大小的需求,类似于 微信中设置字体大小. 那么就需要 app 不跟随系统字体大小调整而变化,找到了两个方法. 方法1: 重写 getResource() 方法,修改 configu ...
- 【Android初级】使用TypeFace设置TextView的文字字体(附源码)
在Android里面设置一个TextView的文字颜色和文字大小,都很简单,也是一个常用的基本功能.但很少有设置文字字体的,今天要分享的是通过TypeFace去设置TextView的文字字体,布局里面 ...
- 我的Android进阶之旅------>关于使用Android Studio替换App的launcher图标之后仍然显示默认的ic_launcher图标的解决方法
前言 最近做了一个App,之前开发该App的时候一直以来都是默认的launcher图标启动的, 今天美工换了一个App的launcher 图标,因此在Android Studio中将默认的lanche ...
- Android实现自定义字体
介绍 最近在看开源项目的时候,发现里面涉及到了自定义字体,虽然自己目前还用不到,但是动手demo笔记记录一下还是有必要的,没准哪天需要到这个功能. 原理 1.其实实现起来非常简单,主要是用到了Type ...
- Android 更换系统字体......
Android 更换系统字体...... 原文:http://vision-apps.blogspot.hk/2012/02/android-better-way-to-apply-custom-fo ...
- 【Android端 APP GPU过度绘制】GPU过度绘制及优化
一.Android端的卡顿 Android端APP在具体使用的过程中容易出现卡顿的情况,比如查看页面时出现一顿一顿的感受,切换tab之后响应很慢,或者具体滑动操作的时候也很慢. 二.卡顿的原因 卡顿的 ...
- Android开发App工程结构搭建
本文算是一篇漫谈,谈一谈关于android开发中工程初始化的时候如何在初期我们就能搭建一个好的架构. 关于android架构,因为手机的限制,目前我觉得也确实没什么大谈特谈的,但是从开发的角 ...
- iOS和Android的app界面设计规范(转)
记录一下iOS和Andoird的界面设计规范,方便进行标准的产品设计,并与设计师顺畅沟通 iOS篇 界面尺寸 设备 分辨率 状态栏高度 导航栏高度 标签栏高度 iPhone6 plus 1242×22 ...
- Android手机app启动的时候第一个Activity必须是MainActivity吗
原文:Android手机app启动的时候第一个Activity必须是MainActivity吗 Android手机APP启动的第一个Activity是可以自己设置的,不是必须的MainActivity ...
随机推荐
- IISExpress配置文件
ASP.NET MVC IISExpress配置文件的一个坑 现象: 昨天在处理PBS系统问题的时候意外发现两个js错误(而同样的代码在同事机器上都没有问题),如下图. 图1 图2 图3 原因分析: ...
- SQL点滴35—SQL语句中的exists
原文:SQL点滴35-SQL语句中的exists 比如在Northwind数据库中有一个查询为 SELECT c.CustomerId,CompanyName FROM Customers c WHE ...
- HDOJ 5063 Operation the Sequence
注意到查询次数不超过50次,那么能够从查询位置逆回去操作,就能够发现它在最初序列的位置,再逆回去就可以求得当前查询的值,对于一组数据复杂度约为O(50*n). Operation the Sequen ...
- SD卡添加文件,添加不进去,报 Read-only file system错误
android 模拟器手机如何添加文件到sd卡? 在DDMS中直接添加文件到模拟器sd卡如果出现错误类似:Failed to push XXXXX.txt on emulator- : Read-on ...
- WCF RIA Services异常
.svc处理程序映射缺失导致的WCF RIA Services异常 在确定代码.编译结果和数据库都正常的情况下,无法从数据库取到数据.错误提示:Sysyem.Net.WebException:远程服务 ...
- 正则表达式测试分析工具Expresso
正则表达式测试分析工具Expresso 一个正则表达式的小工具--myRegexHelper 把以前做的一个功能抽取出来做成一个小的正则表达式测试工具.没什么特色,有两点功能: 一.方便的测试正则 ...
- ListNode线性表
不常用,可以看一下实现原理 namespace UnilateralismChainTable { // 结点类 public class ListNode { public ListNode(int ...
- 创建FTP的Site并用C#进行文件的上传下载
创建FTP的Site并用C#进行文件的上传下载 文件传输协议 (FTP) 是一个标准协议,可用来通过 Internet 将文件从一台计算机移到另一台计算机. 这些文件存储在运行 FTP 服务器软件的服 ...
- c#中解决winform中控件不能输入汉字的办法
设置控件的ImeMode属性 如: textBox.ImeMode = System.Windows.Forms.ImeMode.On; 其中枚举有如下值:
- 集群管理工具Salt
集群管理工具Salt 简介 系统管理员(SA)通常需要管理和维护数以百计的服务器,如果没有自动化的配置管理和命令执行工具,那么SA的工作将会变得很繁重.例如,要给集群中的每个服务器添加一个系统用户,那 ...