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 ...
随机推荐
- Appium Android Bootstrap源码分析之控件AndroidElement
通过上一篇文章<Appium Android Bootstrap源码分析之简介>我们对bootstrap的定义以及其在appium和uiautomator处于一个什么样的位置有了一个初步的 ...
- 项目笔记---CSharp图片处理
原文:项目笔记---CSharp图片处理 项目笔记---CSharp图片处理 最近由于项目上需要对图片进行二值化处理,就学习了相关的图片处理上的知识,从开始的二值化的意义到动态阀值检测二值化等等,并用 ...
- 多线程下HashMap的死循环是如何产生的
前言 HashMap不是线程安全的,如果需要在多线程环境中使用Map,那么我们可以使用ConcurrentHashmap. 1.举例说明: package com.test; import java. ...
- 更改MYSQL数据库不区分大小写表名
今天郁闷死了,在LINUX下调一个程序老说找不到表,但是我明明是建了表的,在MYSQL的命令行下也可以查到,为什么程序就找不到表呢? 后来请教了一个老师才搞定,原来是LINUX下的MYSQL默认是要区 ...
- ps入门教程:裁剪工具、修复画笔工具、图章工具的使用
本节课程主要内容:学习裁剪工具.污点修复画笔工具.修复画笔工具.修补工具.套索工具.红眼工具.仿制图章工具和图案图 章工具的应用.----------------------------------- ...
- 【值得收藏】Mathematica数值计算工具的学习资料汇编【可免费下载】
Mathematica学习教程 Mathematica是一款科学计算软件,很好地结合了数值和符号计算引擎.图形系统.编程语言.文本系统.和与其他应用程序的高级连接.Mathematica与Matlab ...
- Jetbrains 系列神器
PRODUCTS IntelliJ IDEA ReSharper WebStorm PhpStorm PyCharm RubyMine AppCode YouTrack TeamCity dotTra ...
- Js模块模式
模块模式 索引 引子 什么是模块模式 命名空间模式 声明依赖 私有和特权成员 即时函数 揭示模块模式 结语 引子 这篇算是对第9篇中内容的发散和补充,当时我只是把模块模式中的一些内容简单的归为函数篇中 ...
- queue,指针求最短路的区别
这里以spfa为例://都用邻接表存边: 指针: int h=1,t=1; q[h]=x; while(h<=t){ int u=q[h]; vis[u]=0; for(int i=head[u ...
- [译]反-反汇编 & 混淆 #1: 苹果没有遵循自己制定的Mach-O规范?
原文地址:http://reverse.put.as/2012/02/02/anti-disassembly-obfuscation-1-apple-doesnt-follow-their-own-m ...