摘要: 在一个应用中,我需要在所有的UI组件中使用客户提供的字体。这听起来似乎是个很稀松平常的任务,不是吗?是的,我当时也是这么想的。然后我震惊了,Android竟然没有提供一个简单优雅的方式来做这件事情!

在一个应用中,我需要在所有的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)。

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="View with custom font"/>

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等等),而无需考虑界面的布局层级如何。

标准(左)与自定义(右)字体的用法。

Standard (left) and Custom (right) fonts usage.

这是怎么做到的?非常简单:

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框架,等以后引入了,使用第二种注入,写起来应该是很爽的。

保持更新。

参考

DI框架

ButterKnife

android字体好看,Android:更好的自定义字体方案相关推荐

  1. Android:更好的自定义字体方案

    http://ryanhoo.github.io/blog/2014/05/05/android-better-way-to-apply-custom-font/ 情景 解决方案 1)Android默 ...

  2. androidstudio使用mac字体_如何在Android Studio编写的项目中使用自定义字体

    有很多方法可以在字段上设置自定义字体系列,我使用如下所示. 要将字体添加为资源,请在Android Studio中执行以下步骤: 1)右键单击res文件夹,然后转到新建> Android资源目录 ...

  3. 微信小程序设置字体无效_微信小程序自定义字体及自定义图标问题说明

    自定义图标及自定义字体,一直是很多小程序开发者的心病,其实本站是很多解决方案的,为了集中起来,方便直接跳过此坑,我特别做了这次针对字体及字体图标的跳坑: 相关讨论: Q:小程序开发时能否使用我们自定义 ...

  4. java加载字体文件_Java的加载自定义字体文件(.TTF)

    我在下面这段代码中使用,并将其与该堆栈跟踪出现:Java的加载自定义字体文件(.TTF) java.io.FileNotFoundException: font.ttf (No such file o ...

  5. html自定义字体缓存,PixiJS:加载自定义字体

    Environement: Xampp,Firefox,Pixijs,HTML,CSS 现在我尝试加载自定义字体. 我第一次加载我的Pixijs项目应运行的页面时,字体没有显示,控制台显示一些错误消息 ...

  6. 微信小程序中使用字体库_小程序使用自定义字体库

    一.使用前端字体库 小程序前端默认不支持woff2/woff文件加载.但浏览器支持base64编码图片解析. 处理方案蒋woff2转码成base64编码即可. 自定义前端库使用阿里iconfont的即 ...

  7. 使用位图字体工具BMFont从图片生成自定义字体

    上一篇转了别人的一篇文章,讲了BMFont的基本用法.对BMFont比较陌生的同学请点击这里先去学习:http://blog.csdn.net/keshuiyun/article/details/99 ...

  8. iphone引用自定义字体 html,在iphone中使用自定义字体

    1.确定你的项目工程的resouce下有你要用的字体文件(.ttf,.odf). 2. 然后在你的工程的Info.plist文件中新建一行(Add Row),添加key为:UIAppFonts(在我的 ...

  9. android 字体编程,Android编程之Calligraphy:Android 自定义字体库

    Calligraphy是android 自定义字体库 添加依赖 Download from Maven Central (.jar) OR Java dependencies { compile 'u ...

最新文章

  1. solrj操作单机solr
  2. BZOJ1021 [SHOI2008]循环的债务
  3. QT学习:目录操作与文件系统
  4. @transactional注解_为啥同一个类中普通方法调用Spring注解方法,注解会失效?看完你就明白,So easy!...
  5. Linux ss 热点,在Linux系统下的ss命令(socket statistics)各种使用示例
  6. bzoj 1934 最小割
  7. android视频录制(调用系统视频录制),生成缩略图
  8. 年增代码 12.9 亿行,每天完成需求近 4000 个,鹅厂程序员秘密大爆料!
  9. CnBlogs博文demo演示技巧比较:jsfiddle完胜
  10. proxmoxve打造云桌面_最大亮点!山东众志电子为山东财经大学东方学院打造首个200点位云桌面考场...
  11. 稳压二极管 参数说明
  12. 【通俗易懂系列】深度可分离卷积
  13. java项目-第90期基于ssm的嘟嘟二手书商城系统
  14. 学渣的刷题之旅 leetcode刷题 2. 两数相加
  15. 本体开发日记03-理解代码
  16. 2021年电工(初级)考试题及电工(初级)最新解析
  17. mysql mts_MySQL新特性MTS
  18. python爬快手个人介绍个性_快手个人介绍个性霸气说说_江湖一碗茶喝完各自爬...
  19. stm8s103k3 周期 捕获_STM8S003K3如何用定时器中断处理捕获脉冲?
  20. PCL- 最小二乘法拟合平面

热门文章

  1. C语言训练-阶乘和数
  2. git撤销pull回滚到本地pull前版本
  3. 如何使用计算机视觉进行人脸识别和测试?
  4. 8亿多人使用百度搜索,年增长7%,这10个免费流量入口必须把握!
  5. php手机上日程管理软件,手机日程管理软件哪款好用?5款日程管理软件推荐
  6. ARM开发板移植android4.0流程
  7. 十张图,数据分析如何赋能销售
  8. python爬取豆瓣排名前250部电影封面
  9. stm32通过wifi模块实现手机远程控制灯与舵机
  10. 2017lao蒋全程2017基础班三[长难句]