中国领先的IT技术网站
|
|
创建专栏

利用 AppCompatDelegate ,半小时就能在成熟项目上全局替换字体!

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

作者:张旸|2017-09-30 08:45

沙龙活动 | 去哪儿、陌陌、ThoughtWorks在自动化运维中的实践!10.28不见不散!


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

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

期待你持续关注。

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

Android 字体修改概述|开篇

修改字体需要了解 Typeface 的所有细节

简单粗暴的方式,修改字体

利用反射,修改全局字体

一、前言

之前介绍过不少替换字体的方案,本篇再介绍在一个成熟项目上,无缝替换字体的一种解决方案。

其思路就是利用 Support v7 包中的 AppCompatActivity 的控件代理的思路,通过替换 AppCompatDelegate 对象,来实现将原本的 TextView 替换成我们自定义的,可修改字体的 FontTextView ,从而达到替换字体的目的。

使用本方案的前提是你使用的是 AppCompatActivity。

好了,下面进入主题。

二、Support v7 的代理思路

这里说的 Android Support v7 包内的代理思路,主要是通过 AppCompatDelegate 来实现的,我们先来了解一下它的原理。

AppCompat 在最开始出现在 v7 包中的时候,其实作用非常的小,只是为了让 Api Level 7+ 的设备,也可以使用 ActionBar 。

而在 Support v7:21 版本之后,AppCompat 承担了更多的责任,可以为 API Level 7+ 的设备带来 Material Color Palette 、Widget 着色、ToolBar 等功能。而且之前推荐使用的 ActionBarActivity 也不再推荐使用,取而代之的是 AppCompatActivity。

AppCompatActivity 其实内部的实现原理也和之前的 ActionBarActivity 不同,它是通过 AppCompatDelegate 来实现的。AppCompatActivity 将所有的生命周期相关的回调,都交由 AppCompatDelegate 来处理。

但是实际上它们并没有直接的关联关系,我们也可以直接使用 AppCompatDelegate 来放入我们自己实现的 Activity 中,但是这样就会更麻烦,一般也不推荐这样使用。

1、AppCompat 因何存在

AppCompat 为了支持 MD 的效果,需要其内部的控件都具有自动着色功能,这样可以保持 App 在设计上具有一致的体验和提高认可度。而这些是原本的 UI 控件所不具备的,所以它只好将其需要的 UI 控件全部重写一遍来支持这个效果。

这些被重写的 UI 控件,都在 android.support.v7.widget 包下面:

可以看到这些被重写的 UI 控件都是 AppCompat 开头的,但是如果重写了这么多控件,现有项目直接硬替换起来,工作量就会非常大,所以 AppCompatDelegate 这种以代理的方式自动为我们替换所使用的 UI 控件的功能就非常的有必要了。

2、AppCompatDelegate 是如何工作的

在 AppCompatActivity 中,使用 getDelegate() 方法来获得 AppCompatDelegate 对象的。

而这个 AppCompatDelegate.create() 方法就是其做代理支持的实现。

可以看到它在其中,分别根据不同的 Api Level 进行不同的实现,而且最低能支持到 Api Level 9。

虽然这里看到它通过 Api Level 做了区分判断来做具体的实现,但是类似这种 AppCompatDelegateImplVxx 的类,都高版本的继承低版本的。而 AppCompatDelegateImplV9 中,就是通过 LayoutInflaterFactory 接口来实现 UI 控件替换的代理。

在解析 ViewTree 的时候,会调用 createView() 方法来得到 View 对象,在其中,又是通过 mAppCompatViewInflater.createView() 来真实的获取 View 的。

而在 mAppCompatViewInflater.createView() 中,就是通过 UI 控件的名称,来替换掉我们需要的 AppCompatXxx 的 UI 控件。

所以到这里,就可以发现,如果我们也需要利用 AppCompatDelegate 来替换掉我们需要的 UI 控件,只需要自己实现一个 AppCompatDelegate 以及其中的 callActivityOnCreateView() 方法。在实际使用的 AppCompatActivity 的父类中,重写 getDelegate() 方法,将方法的返回值替换成我们之前修改过的 AppCompatDelegate ,就可以实现自动替换 UI 控件了。

三、全局替换字体

看到这里,相信已经了解到 AppCompatDelegate 的原理了,也知道我们接下来如何利用它来替换全局的 TextView,从而达到替换字体的目的。

首先,我们需要有一个可修改字体的 FontTextView 控件,它是继承自 AppCompatTextView 的。

FontTextView 控件的逻辑非常的简单,就是从 assets 中取出字体,然后再 set 到 TextView 上去。

再在项目内,建立一个 android.support.v7.app 的 Package。在其中,新建一个 FontAppCompatActivity 的类,它是继承自 AppCompatActivity。

在这里,通过重写 callActivityOnCreateView() 方法,在识别到是 TextView 之后,将我们重写的 FontTextView 构造好并返回出去,来达到控件替换的目的。

当然,实际项目中,你还需要 EditTextView、Button 以及你项目内用到的其它用于显示文字的自定义控件。

需要注意的是,这里的 FontCompatActivity 一定要放在 android.support.v7.app 包下,否者AppCompatDelegateImplV14 你将无法继承它。

为了方便,我将 FontTextView 也放在此包下了,之中的结构如下:

到这里,就已经完成了基本的替换工作,只需要替换我们 Activity 的父类即可。

 

最后,运行起来看看效果,完美的一次替换。

【本文为51CTO专栏作者“张旸”的原创稿件,转载请通过微信公众号联系作者获取授权】

戳这里,看该作者更多好文

【编辑推荐】

  1. 用SnackBar替换掉Toast?看完再决定
  2. Android字体修改,所有的细节都在这里 | 开篇
  3. 想修改 Android 字体,你需要先了解一下 Typeface!!!
  4. Android中以粗暴的方式替换全局字体
  5. 全局修改默认字体,通过反射也能做到
【责任编辑:武晓燕 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

热门职位+更多

× Python最火的编程语言