序列也可以通过反射实现。在Android下使用自定义字体已经是比较普遍的需求,最近做了比较深入的研究。然后按照惯例,我再发一篇Android字体修改的文章,但是写下来发现内容挺多的,所以决定拆分成几篇文章详细讲解(也许五篇文章)。主要会是一些常用的字体替换方案,最后会介绍一些全局替换方案,当然也会包括最新的“FontsinXML”方案。期待您的持续关注。本文是本系列的第四篇文章。有兴趣的可以看看之前发表过的文章。Android字体修改概述|一开始修改字体,需要简单粗暴的了解Typeface的所有细节。修改字体一、前言本文仍属于安卓字体修改系列。更好的方案可能更好,但不一定最适合你当前的项目。今天介绍的就是其中之一,在Typeface中利用反射修改一个字体,达到全局替换的目的。2.替换默认字体的思路本文中的很多准备知识点在上一篇文章中应该已经讲清楚了。有兴趣的可以看全文,《想修改 Android 字体,你需要先了解一下 Typeface!!!》。为了保证逻辑的完整性,这里给出一个大概的思路。2.1修改一个Typeface的默认字体,首先要明确一点,在Android中,所有操作字体的动作都会用到Typeface类。而系统默认的一些字体也会在Typeface加载的时候进行初始化,因为这些步骤都是在它的静态代码块中完成的。而这些字体会被定义为staticfinal,所以一般我们是不能修改的。但是我们可以使用反射来修改标记为staticfinal的常量,后面会详细介绍。也就是说,我们只需要在初始化时替换一个默认字体,然后在Theme中将默认字体标记为这个字体就可以达到替换的目的。2.2TextView中的默认字体在TextView的构造函数中,设置字体的方法是setTypefaceFromAttrs(),该方法的方法签名如下。该方法的参数中,如果familyName为null,则根据传入的typefaceIndex设置对应的字体,传入setTypeface()方法。我们来看看在TextView的构造方法中获取这些参数的地方。默认什么都不设置的情况下,familyName为null,typefaceIndex为-1。这两个参数会先从TextAppearance中读取属性,然后再从TextView自身设置的xml属性中读取,后者会覆盖前者。但是,typefaceIndex还有一些其他的操作。比如当inputType为password时,会强制改为MONOSPACE。最后,将处理后的结构传递给setTypefaceFromAttrs()方法。通过这些细节,我们可以了解到,在某些情况下,可以保证TextView使用我们默认加载到Typeface中的一种字体。条件是:fontFamily==null&&typefaceIndex!=-12.3在Theme中,修改字体为默认字体样式。对于一些默认的字体样式,可以直接在Theme中设置,其优先级低于页面布局的xml中为TextView设置的字体样式,但如果不设置,则Theme中的设置生效。对此无话可说。我这里使用的主题是AppTheme,所以可以修改里面的android:typeface。3、通过反射修改字体到这里基本的概念已经解释清楚了,下面我们开始真正的写代码来替换字体。3.1修改主题在App主题中,修改android:typeface为serif。请注意,此处随机选择默认字体。其实用monospace也是可以的,只要和我们后面替换的字体一致即可。当然这里不推荐monospace,因为TextView本身有一些逻辑可以将typefaceIndex设置为monospace,所以最好不要替换。3.2通过反射修改Typeface字体在Typeface中,有一些默认字体标记为staticfinal,因为在上一步的Theme中,设置了serif,所以我们这里直接替换即可。完整的方法很简单,通过反射获取Typeface.SERIF,然后使用反射修改为我们需要的字体即可。因为这里修改了staticfinal的值,所以需要额外调用setAccessible()方法,将AccessibleObject中的overide修改为true。这个标记的意思是关闭重写这个字段的安全检查,这样我们就可以替换staticfinal字段了。3.3入口处调用替换的方法接下来就清楚了,我们只需要在App启动时调用changeDefaultFont()方法即可。这里可以直接在Application.onCreate()方法中调用。3.4验证运行结果这没什么,写个Demo,正常使用TextView就可以了。【本文为专栏作家“张扬”原创稿件,转载请微信公众号联系作者获取授权】点此查看该作者更多好文
