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 ...
随机推荐
- Light OJ 1316 A Wedding Party 最短路+状态压缩DP
题目来源:Light OJ 1316 1316 - A Wedding Party 题意:和HDU 4284 差点儿相同 有一些商店 从起点到终点在走过尽量多商店的情况下求最短路 思路:首先预处理每两 ...
- 新手可以学习cocos2dx 3.0 组态(两)
这主要是关于cocos3.0 组态,鉴于互联网已经有很多这样的文章.所以我简单谈一下: 1.python2.7 因为cocos目新建是用python脚本做的,至于为什么不用python3.x 那么请 ...
- Linux解决:svn: Can't connect to host '*.*.*.*': 因为连接的方没有正确回答或连接在以后的时间
svn服务启动,在server在可使用命令将文件检查,但它不能检测其他计算机.已经提出: "svn: Can't connect to host '*.*.*.*': 因为连接方在一段时间后 ...
- 【SSH三个框架】Hibernate第八部分基础:经营-many关系
在Hibernate在-many关系.它通常不使用.由于当数据库查询复杂度太高时. 我们在这里做的是学生和教师,学生可以有多个老师,教师可以有多个学生. watermark/2/text/aHR0cD ...
- 【蜗牛—漫漫IT路之大学篇(九)
】
再来一篇叨叨的博客 近期,状态还是那个状态,人还是那个人. 前两天,感冒了,可能是宿舍阴面的事吧.然后,中午睡觉的时候穿着短袖披了一件外套,然后鼻子就不通气了.只是,前天晚上,我骑着崔国强的车子跑了不 ...
- js实现在新标签页打开页面
这种方法打开新标签页要在IE9+以上浏览器才可以! <html> <head> <meta http-equiv="Content-type" con ...
- Failed to issue method call: Unit mysql.service failed to load: No such file or directory解决的方式
Failed to issue method call: Unit mysql.service failed to load: No such file or directory解决的方式 作者:ch ...
- Controller 的 Action 只接受 Ajax 请求
ASP.NET MVC 使 Controller 的 Action 只接受 Ajax 请求. 2014-08-27 14:19 by h82258652, 555 阅读, 2 评论, 收藏, 编辑 首 ...
- quartz_spring 定时器配置
quartz:石英,表达精确准时的意思. quartz-all-1.6.1.jar 主要用于定时任务管理. <?xml version="1.0" encoding=&quo ...
- ListNode线性表
不常用,可以看一下实现原理 namespace UnilateralismChainTable { // 结点类 public class ListNode { public ListNode(int ...