前言
android中,应用字体字号切换有很多种方式,其中,利用attrs属性和dimend属性,配合Theme的?符号可以非常便利的达到目的,同时还可以对字体字号进行简单的适配,只需要在项目开发初始阶段花费十分钟做完以下几步即可。
演示效果

GitHub链接
字体切换和简单适配Demo------FontSiceDemo
原理
让我们先看一下android的SDK文档/docs/guide/topics/resources/accessing-resources.html中对资源文件? 符号的说明:
A style attribute resource allows you to reference the value of an attribute in the currently-applied theme. Referencing a style attribute allows you to customize the look of UI elements by styling them to match standard variations supplied by the current theme, instead of supplying a hard-coded value. Referencing a style attribute essentially says, "use the style that is defined by this attribute, in the current theme."
instead of the at-symbol (@), use a question-mark (?) , and the resource type portion is optional. For instance:?[<package_name>]:[<resource_type>/]<resource_name>.
主要看最后三句话,翻译过来就是,在当前theme中使用在资源文件(即res目录)中通过attribute(即attr标签)定义的样式,可通过 ?<包名:>(省略的话就指向本应用包名)资源名为resource_name的resource_type 的方式替代@的符号.
注:resource_type指的就是res目录中在<resources><resources/>标签内定义的各种资源类型,比如我们常用的colors.xml,styles.xml,string.xml文件根标签都是<resources><resources/>
例如

上面的Button中, ?android:textColorHighlight 表示引用android包下的名为textColorHighlight的资源, 而 ?height 表示引用当前的Theme内,名为 height 的资源,只要我们ctrl点进去,就会看到这个values.xml文件

使用的就是attr标签定义这个 height,而values.xml是系统文件,并且根据文档的解释,这个height必然在系统的某个Theme中使用到了,找一找发现

所以,我们可以利用系统的用法来轻易实现字体字号切换功能.
实现流程
1.第一步,在res目录的attr文件中定义以下属性,这里命名为textsice+,可以根据项目实际需求来决定字号范围:一般6-28范围即可:

2.第二步,我们在dimens文件中定义好以下属性,这里命名为fontsice++,并设定每个属性好对应的sp(用sp会随手机系统字体放大而放大,所以建议使用dp,这样可以不用去考虑系统字体变化后的适配问题),以下用a,b,c依次代表:小号 默认 大号 字体,可以根据项目需求定义多套:

3.第三步,在style文件中,我们需要分别定义对应a,b,c三个字号的Theme主题,然后我们将在attr文件中定义的属性textsice+指向dimen文件中对应的fontsice++值,如下面,AppThemSmall主题的textsice+属性对应的是fontsice+a的dimen引用:

4.然后,我们在自己的xml中设置字体大小的属性引用都改成以下方式,我习惯命名规律是values目录:?textsize16对应16sp(用sp会随手机系统字体放大而放大,所以建议使用dp,这样可以不用去考虑系统字体变化后的适配问题,后面会讲到如何适配不同屏幕密度):

5.最后,使用SP配置文件,保存用户的字号选择,在项目的Activity基类的setContentView()方法执行之前通过Activity的setTheme()设置对应的Theme即可:

6.简单适配不同屏幕密度:
这个其实很简单,我们先创建不同密度的values文件,然后把前面在values文件中创建的dimens文件复制到其它各个values文件中,其中values-xxhdpi中的dimens文件和values文件中的dimens文件的fontsize++属性的sp值相同,values-xxxhdpi中的dimens文件的需要比xxhdpi的都递增1sp,而xhdpi-values和hdpi-values的dimens文件相对于xxhdpi-values的dimens文件,fontsize++属性分别递减1sp,通过以上设置,基本可以让各个屏幕密度下的字体不会显得过大或过小(用sp会随手机系统字体放大而放大,所以建议使用dp,这样可以不用去考虑系统字体变化后的适配问题);
具体操作可以查看我的Github上面的Demo;

注意事项
在自定义控件中,如果使用到canvas.drawText()来绘制text文本,若需要和系统的控件一样实现字体字号切换,可以通过一个全局类如Global,声明好对应textsice+的静态成员,在基类Activity调用了setTheme()方法后,通过以下代码取出theme的各个textsice+属性对应的sp值,再在自定义View中使用Global的这些静态成员:
getTheme().resolveAttribute(R.attr.textsize10,new TypedValue(),true);
结语
整个准备过程大概只需10来分钟,当然缺点也是有的,就是切换字号是需要重启app的,至少已经创建的Activity是需要重新启动才会生效,不过用起来还是蛮方便的。
后面会分享更多的常用控件和讲解现在已经应用比较广泛的MVP框架,不足的地方,谢指出!
网友评论