Android 更换系统字体......
Android 更换系统字体......
原文:http://vision-apps.blogspot.hk/2012/02/android-better-way-to-apply-custom-font.html
在一个应用中,我需要在所有的UI组件中使用客户提供的字体。这听起来似乎是个很稀松平常的任务,不是吗?是的,我当时也是这么想的。然后我震惊了,Android竟然没有提供一个简单优雅的方式来做这件事情!
所以,在这篇文章中我会展示Android提供的默认方法,然后我会分享更加简单优雅的解决方案。
情景
你需要为整个应用替换自定义字体。
解决方案
1)Android默认方法 #1
你可以通过ID查找到View,然后挨个为它们设置字体。在单个View的情况下,它看起来也没有那么可怕。
Typeface customFont = Typeface.createFromAsset(this.getAssets(), "fonts/YourCustomFont.ttf");
TextView view = (TextView) findViewById(R.id.activity_main_header);
view.setTypeface(customFont);
但是在很多TextView、Button等文本组件的情况下,我敢肯定你不会喜欢这个方法的。:D
2)Android默认方法 #2
你可以为每个文本组件创建一个子类,如TextView、Button等,然后在构造函数中加载自定义字体。
public class BrandTextView extends TextView {
public BrandTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public BrandTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BrandTextView(Context context) {
super(context);
}
public void setTypeface(Typeface tf, int style) {
if (style == Typeface.BOLD) {
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/YourCustomFont_Bold.ttf"));
} else {
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/YourCustomFont.ttf"));
}
}
}
然后只需要将标准的文本控件替换成你自定义的就可以了(例如BrandTextView替换TextView)。
<com.your.package.BrandTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="View with custom font"/>
<com.your.package.BrandTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="View with custom font and bold typeface"/>
还有,你甚至可以直接在XML中添加自定义的字体属性。要实现这个,你需要定义你自己的`declare-styleable`属性,然后在组件的构造函数中解析它们。
为了不占篇幅介绍这么基础的东西,这里有一篇不错的文章告诉你怎么自定义控件属性。
http://kevindion.com/2011/01/custom-xml-attributes-for-android-widgets/
在大多数情况下,这个方法还不赖,并且有一些优点(例如,切换字体粗细等等,字体可以在组件xml文件的typeface属性中定义)。但是我认为这个实现方法还是太重量级了,并且依赖大量的模板代码,为了一个替换字体的简单任务,有点儿得不偿失。
3)我的解决方案
理想的解决方案是自定义主题,然后应用到全局或者某个Activity。
但不幸的是,Android的`android:typeface`属性只能用来设置系统内嵌的字体,而非用户自定义字体(例如assets文件中的字体)。这就是为什么我们无法避免在Java代码中加载并设置字体。
所以我决定创建一个帮助类,使得这个操作尽可能的简单。使用方法:
FontHelper.applyFont(context, findViewById(R.id.activity_root), "fonts/YourCustomFont.ttf");
并且这行代码会用来加载所有的基于TextView的文本组件(TextView、Button、RadioButton、ToggleButton等等),而无需考虑界面的布局层级如何。
标准(左)与自定义(右)字体的用法。

这是怎么做到的?非常简单:
public static void applyFont(final Context context, final View root, final String fontName) {
try {
if (root instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) root;
for (int i = 0; i < viewGroup.getChildCount(); i++)
applyFont(context, viewGroup.getChildAt(i), fontName);
} else if (root instanceof TextView)
((TextView) root).setTypeface(Typeface.createFromAsset(context.getAssets(), fontName));
} catch (Exception e) {
Log.e(TAG, String.format("Error occured when trying to apply %s font for %s view", fontName, root));
e.printStackTrace();
}
}
正如你所看到的,所需要做的仅仅是将基于TextView的文本组件从布局中遍历出来而已。
你可以在这里下载到示例代码,里面有`FontHelper`的具体用法。
译者注
在多个项目中,我都碰到过类似的需求,早期采用的是第二种实现方法,但是缺点在于对于第三方组件,你需要去修改别人的代码,才能实现自定义字体,这恰恰违反了OC(Open & Close)原则,对扩展开放,对修改封闭。
刚看到第三种的时候,也是惊为天人,姑且不说结果,我觉得这种活跃的思路非常重要,很值得学习参考。
但是最后被team里的人否决了,理由是违背组件设计原则,实现方式略嫌粗暴。后来我仔细想想,一个是要做好内存管理(似乎会引起内存问题),视图状态改变,也要重复加载(横竖屏、onResume等),也绝对不是简单的活儿。
所以暂定使用第一种方法,typeface使用单例,需要时设置字体。
我个人觉得第一种还是个体力活,而且到后来,这个代码重复率还是非常高的,这又违背了DRY原则。
在地铁上的时候,突然想到DI(Dependency Inject)。已经有一些DI的框架,如ButterKnife,那写出来应该是这样:
@CustomFont(R.id.textView) TextView textView
or
@InjectView(id=R.id.textView, customFont=true) View anyView
@InjectView(id=R.id.textView, customFont=true, font="fonts/ltfz.ttf") View anyView
这样写出来代码相比重复写setTypeface要好一些。
目前我们的项目还没有使用这类DI框架,等以后引入了,使用第二种注入,写起来应该是很爽的。
保持更新。
参考
转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-)
http://ryanhoo.github.io/blog/2014/05/05/android-better-way-to-apply-custom-font/
Android 更换系统字体......的更多相关文章
- [Android] 字体使用dp单位避免设置系统字体大小对排版的影响
[Android] 字体使用dp单位避免设置系统字体大小对排版的影响 以魄族mx3为例,在设置->显示->字体大小中能够选择字号大小例如以下图: 图1. 魄族mx3 会导致软件在有固定定高 ...
- Android系统字体规范
我们在做Android移动APP设计的时候,字号的选择也是很让人头疼,转载一份有关Android系统字体规范,如果在做Android项目的用户应该看看,如果有任何建议欢迎在留言处与我们交流探讨. 主要 ...
- Android: 设置 app 字体大小不跟随系统字体调整而变化
在做 app 内字体大小的需求,类似于 微信中设置字体大小. 那么就需要 app 不跟随系统字体大小调整而变化,找到了两个方法. 方法1: 重写 getResource() 方法,修改 configu ...
- Android 系统字体和颜色样式
Android 字体和颜色 对于能够显示文字的控件(如TextView EditText RadioButton Button CheckBox Chronometer等等),你有时需要控制字体的大小 ...
- Linux 桌面系统字体配置要略
字体显示效果测试 这一段是为了测试宋体字的显示效果,包括宋体里面自带的英文字体,“This is english,how does it look like?”.这一行是小字.后面几个字是加粗的宋体. ...
- android 修改系统的dialog样式
android 修改系统的dialog样式 一.觉得自定义配置文件麻烦?那就来修改系统自定义XML文件来实现修改系统dialog的样式吧. 如果是在XML中样式:首先来说下样式. 在 Style.x ...
- Android实现系统下拉栏的消息提示——Notification
Android实现系统下拉栏的消息提示--Notification 系统默认样式 默认通知(通用) 效果图 按钮 <Button android:layout_width="match ...
- Linux 桌面玩家指南:04. Linux 桌面系统字体配置要略
特别说明:要在我的随笔后写评论的小伙伴们请注意了,我的博客开启了 MathJax 数学公式支持,MathJax 使用$标记数学公式的开始和结束.如果某条评论中出现了两个$,MathJax 会将两个$之 ...
- Android之系统架构
Android 是Google开发的基于Linux平台的开源手机操作系统.它包括操作系统.用户界面和应用程序 —— 移动电话工作所需的全部软件,而且不存在任何以往阻碍移动产业创新的专有权障碍.Andr ...
随机推荐
- win7系统64位plsql的设置
1. Instant Client Downloads for Microsoft Windows (32-bit) 我下载的是: instantclient-basic-win32-11.2.0.1 ...
- C# 中的常用正则表达式大全
这是从网上找来的,收藏一下备用,用到之处可以节省不少时间哦! 只能输入数字: "^[0-9]*$" . 只能输入n位的数字:"^\d{n}$". 只能输入 ...
- Oprofile安装与使用探索
本文分别尝试了oprofile在x86平台和龙芯平台上的安装 一:oprofile的安装与配置(intel+ubuntu12.04) I. Oprofile 安装 Oprofile 包含在 Linux ...
- yum添加源。
本文以centos 7为准.其他版本的linux可能存在一些偏差. 第一:索引文件. 1)repo文件. 1.repo文件是指以repo为结尾的文件.是 仓库源的索引文件.将其添加到yum的repo仓 ...
- C# sliverlight调用WCF服务出现的一个错误
错误提示如下: 尝试向 URI“http://localhost:8396/Service1.svc”发出请求时出错.这可能是由于试图以跨域方式访问服务而又没有正确的跨域策略,或策略不适用于 SOAP ...
- Android 获取图片真实宽高
Resources res = mContext.getResources(); BitmapFactory.Options opts = new BitmapFactory.Options(); o ...
- 使用Python脚本获取指定格式文件列表的方法
在Python环境下获取指定后缀文件列表的方式. 来源stackoverflow 这里简单以*.txt的作为例子. 使用glob(推荐) import glob, os os.chdir(" ...
- MYSQL insert
准备: create table T4(X int ,Y int); 方法 1. insert [low_priority][high_priority][delayed] into table_na ...
- 整体刷新和局部刷新frameset窗口(转)
在项目中,经常会遇到页面分割,最常见的系统或网站的主界面.主页面分为,上面系统简介.下面作者简介.左边系统功能菜单.右边则是菜单真正展示的界面. 遇到这种这种分割页面,大家 ...
- centos vim的安装目录在哪里
[root@test man]# rpm -ql vim-common | grep python/usr/share/vim/vim72/autoload/pythoncomplete.vim/us ...