全局修改默认字体,通过反射也能做到

来源:互联网 发布:计生委招聘 知乎 编辑:程序博客网 时间:2024/05/29 14:12

在 Android 下使用自定义字体已经是一个比较常见的需求了,最近也做了个比较深入的研究。

那么按照惯例我又要出个一篇有关 Android 修改字体相关的文章,但是写下来发现内容还挺多的,所以我决定将它们拆分一下,分几篇来详细的讲解(可能是五篇)。主要会是一些常用的替换字体的方案,最后还会介绍一些全局替换的方案,当然也会包含最新的 『Fonts in XML』的方案。

期待你持续关注。

本篇是本系列的第三篇,之前已经发布的文章,有兴趣可以先看看。

  • Android 字体修改概述|开篇
  • 修改字体需要了解 Typeface 的所有细节

一、前言

前面已经分析了修改字体的所有细节,以及与修改字体相关的 Typeface 类,接下来就开始讨论如何修改全局字体。

本篇会先介绍两种比较粗暴的方式来修改全局的字体。

二、自定义字体相关的控件类

在开始一个新的项目的时候,一般习惯好点的都会定义一个 BaseActivity 和 BaseFragment 来作为页面的基类,这样可以方便我们在之后的时候,对所有页面增加一些统一的逻辑。

不过应该不会有人提前想到要给所有的控件,提前定义一个自定义的控件实现。

但是如果在开发的初期,就已经考虑到字体需要修改的情况的话,是可以重写一些字体显示相关的控件。来达到全局替换字体的作用的。

Android 中,最常用的用来显示字体的控件,就是 TextView,这里就重写一个 TextView 来达到替换字体的效果。

在 TextView 中,可以通过 setTypeface() 方法,为 TextView 设置一个字体,setTypeface() 方法有两个重载方法,无非就是多传递了一个需要设置的 textStyle,用来标记粗体和斜体。

/f-setTypeface.png

其实最终都是调用一个参数的 setTypeface(,它才是设置的关键。

/f-setTypeface1.png

可以看到,设置字体实际上是操作的 mTextPaint,mTextPaint 是 TextPaint 类的对象,直接继承自 Paint,就是一个用来绘制文字的画笔。

那么,我们就可以直接自定义一个 TextView ,在构造函数中,通过 setTypeface() 方法,来修改 TextView 的字体。

主要代码如下:

/f-fontTextView.png

注意,这里还需要考虑在布局中,为我们设定的 FontTextView 设置的 textStyle 属性,可能是粗体或者斜体。

通常设计师为了考虑 App 的 UI 统一性和协调性,一般都会选用一个字体,所以将需要替换的字体封装在 FontTextView 中,也没有什么大的问题。

那么来验证看看实现出来的效果,这里专门选择了一个比较特殊的字体。在布局 xml 文件中,添加三个 FontTextView。

/f-fontxml.png

再来看看运行的效果。

/f-fontimage.png

这里也考虑了在布局中设置的 textStyle,并且一个已经比较倾斜的字体,使用 italic 标记之后,更倾斜了。

这个方法,如果在开发初期,还可以接受,无非就是写布局的时候,需要注意使用自定义的控件,同时还除了 TextView ,还需要重写 Button、EditText 等一系列需要显示文字的控件,说到底还是有点麻烦的。

而且如果是在一个已经成熟的项目上再使用这种方案,改动起来还是很费劲的,基本上就是一通文本替换,改动会比较大一些。

三、遍历 ViewTree,替换字体

在 Android 中,用于显示文本的控件,都是直接或者间接集成自 TextView 的,那么我们只需要找一个合适的时机,遍历布局的 ViewTree,将其中所有 TextView 的子类都获取出来,然后批量修改它们的字体,同样也可以达到全局替换的效果。

/f-replaceroot.png

在这个 replaceCustomFont() 的方法里,回去判断是否继承自 TextView,如果是就替换字体。如果不是,再判断是否是一个 ViewGroup,如果是的话,从其内取出所有的子 View,再递归调用 replaceCustomFont() 方法。

通常,为了在合适的时机修改字体,我们可以将这个方法加在 Activity.onCreate() 方法,或者 Fragment.onCreateView() 方法的后面,修改的地方,相对少一些,不过还需要考虑 ListView、RecyclverView 这种动态生成 View 的逻辑,也需要注意不能遗漏。

举个例子,写一个布局,在 Activity.onCreate() 方法中,调用 replaceCustomFont() 方法。

/f-replascemain.png

最后展现的效果如下。

/f-fontimage.png

使用这种方式,优点是,不需要修改 XML 布局,不需要重写多个控件。只需要在 Inflater View 的之后,调用一下 replaceCustomFont() 方法即可。

缺点也非常的明显,每个页面都需要修改,有动态加载 View 的地方可能会被遗漏,改动相比较之前的方案,稍微少一点。并且违背了组件的设计原则,实现方式也略显粗暴。同时它每次都会递归遍历 ViewTree,性能上多少都会有点影响。

四、小结

本文介绍的几个办法,在实际开发中,可能也用不上。不过不影响我们了解这样的方法。

下期预告

到现在为止,介绍的替换字体的方案,其实并不够优雅。从下期开始,就会开始介绍一些更优雅的方式,在现有项目上,全局的替换字体的一些方案。期待你的持续关注。

公众号二维码.jpg

原创粉丝点击