原文:http://vision-apps.blogspot.hk/2012/02/android-better-way-to-apply-custom-font.html
在一个应用中,我需要在所有的ui组件中使用客户提供的字体。这听起来似乎是个很稀松平常的任务,不是吗?是的,我当时也是这么想的。然后我震惊了,android竟然没有提供一个简单优雅的方式来做这件事情!
所以,在这篇文章中我会展示android提供的默认方法,然后我会分享更加简单优雅的解决方案。
你需要为整个应用替换自定义字体。
你可以通过id查找到view,然后挨个为它们设置字体。在单个view的情况下,它看起来也没有那么可怕。
但是在很多textview、button等文本组件的情况下,我敢肯定你不会喜欢这个方法的。:d
你可以为每个文本组件创建一个子类,如textview、button等,然后在构造函数中加载自定义字体。
然后只需要将标准的文本控件替换成你自定义的就可以了(例如brandtextview替换textview)。
还有,你甚至可以直接在xml中添加自定义的字体属性。要实现这个,你需要定义你自己的<code>`declare-styleable</code>`属性,然后在组件的构造函数中解析它们。
为了不占篇幅介绍这么基础的东西,这里有一篇不错的文章告诉你怎么自定义控件属性。
http://kevindion.com/2011/01/custom-xml-attributes-for-android-widgets/
在大多数情况下,这个方法还不赖,并且有一些优点(例如,切换字体粗细等等,字体可以在组件xml文件的typeface属性中定义)。但是我认为这个实现方法还是太重量级了,并且依赖大量的模板代码,为了一个替换字体的简单任务,有点儿得不偿失。
理想的解决方案是自定义主题,然后应用到全局或者某个activity。
但不幸的是,android的<code>`android:typeface</code>`属性只能用来设置系统内嵌的字体,而非用户自定义字体(例如assets文件中的字体)。这就是为什么我们无法避免在java代码中加载并设置字体。
所以我决定创建一个帮助类,使得这个操作尽可能的简单。使用方法:
并且这行代码会用来加载所有的基于textview的文本组件(textview、button、radiobutton、togglebutton等等),而无需考虑界面的布局层级如何。
标准(左)与自定义(右)字体的用法。
这是怎么做到的?非常简单:
正如你所看到的,所需要做的仅仅是将基于textview的文本组件从布局中遍历出来而已。
你可以在这里下载到示例代码,里面有<code>`fonthelper</code>`的具体用法。
在多个项目中,我都碰到过类似的需求,早期采用的是第二种实现方法,但是缺点在于对于第三方组件,你需要去修改别人的代码,才能实现自定义字体,这恰恰违反了oc(open & close)原则,对扩展开放,对修改封闭。
刚看到第三种的时候,也是惊为天人,姑且不说结果,我觉得这种活跃的思路非常重要,很值得学习参考。
但是最后被team里的人否决了,理由是违背组件设计原则,实现方式略嫌粗暴。后来我仔细想想,一个是要做好内存管理(似乎会引起内存问题),视图状态改变,也要重复加载(横竖屏、onresume等),也绝对不是简单的活儿。
所以暂定使用第一种方法,typeface使用单例,需要时设置字体。
我个人觉得第一种还是个体力活,而且到后来,这个代码重复率还是非常高的,这又违背了dry原则。
在地铁上的时候,突然想到di(dependency inject)。已经有一些di的框架,如butterknife,那写出来应该是这样:
or
这样写出来代码相比重复写settypeface要好一些。
目前我们的项目还没有使用这类di框架,等以后引入了,使用第二种注入,写起来应该是很爽的。
保持更新。
di框架
butterknife
转载声明:ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-)
http://ryanhoo.github.io/blog/2014/05/05/android-better-way-to-apply-custom-font/