image
这个动态图中,首先看到的是
Activity1
,点击换肤,可直接更换界面上的background
,图片的src
,还有textView
的textColor
,跳转Activity2
之后的textView
颜色,在我换肤之前,和换肤之后,是不同的。换肤的过程我并没有启动另外的Activity
,界面也没有闪烁。我在Activity1
里面换肤,直接影响了Activity2
的textView
字体颜色。
**既然给出了效果,那么肯定要给出Demo,不然太没诚意,嘿嘿嘿
github地址奉上:https://github.com/18598925736/HookSkinDemoFromHank**
2. 界面上哪些东西是可以换肤的
上面的换肤动态图,我换了ImageView,换了background,换了TextView的字体颜色,那么到底哪些东西可以换?
答案其实就一句话: **我们项目代码里面 res目录下的所有东西,几乎都可以被替换。
(为什么说几乎?因为一些犄角旮旯的东西我没有时间一个一个去试验…囧)**
具体而言就是如下这些
- 动画
- 背景图片
- 字体
- 字体颜色
- 字体大小
- 音频
- 视频
3. 利用HOOK技术实现优雅的“一键换肤"
- 什么是hook
**如题,我是用hook实现一键换肤。那么什么是hook?
hook,钩子. 安卓中的hook技术,其实是一个抽象概念:对系统源码的代码逻辑进行"劫持",插入自己的逻辑,然后放行。注意:hook可能频繁使用java反射机制···**
"一键换肤"中的hook思路
- "劫持"系统创建View的过程,我们自己来创建View
系统原本自己存在创建View的逻辑,我们要了解这部分代码,以便为我所用.
- 收集我们需要换肤的View(用自定义view属性来标记一个view是否支持一键换肤),保存到变量中
劫持了 系统创建view的逻辑之后,我们要把支持换肤的这些view保存起来
- 加载外部资源包,调用接口进行换肤
外部资源包,是`.apk`后缀的一个文件,是通过`gradle`打包形成的。里面包含需要换肤的资源文件,但是必须保证,要换的资源文件,和原工程里面的文件名`完全相同`.
4. 相关android源码一览
- Activity 的 setContentView(R.layout.XXX) 到底在做什么?
回顾我们写`app`的习惯,创建`Activity`,写`xxx.xml`,在`Activity`里面`setContentView(R.layout.xxx).` 我们写的是`xml`,最终呈现出来的是一个一个的界面上的UI控件,那么`setContentView`到底做了什么事,使得XML里面的内容,变成了UI控件呢?
如果不先来点干货,估计有些人就看不下去了,各位客官请看下图:
image
源码索引:
setContentView(R.layout.activity_main);
—》
getDelegate().setContentView(layoutResID);
OK,这里暴露出了两个方法,getDelegate()
和setContentView()
先看getDelegate
:
这里返回了一个AppCompatDelegate
对象,跟踪到AppCompatDelegate内部,阅读源码,可以得出一个结论:AppCompatDelegate
是 替Activity生成View对象的委托类,它提供了一系列setContentView方法,在Activity中加入UI控件。
那它的AppCompatDelegate
的setContentView
方法又做了什么?
插曲:关于如何阅读源码?在我的上一篇文章 中详细说明了。
但是漏了一个细节:那就是,当你在源码中看到一个
接口
或者抽象类
,你想知道接口的实现类
在哪?很简单…如果你没有更改androidStudio
的快捷键设置的话,Ctrl+T
可以帮你直接定位接口和抽象类的实现类
.
用上面的方法,找到setContentView的具体过程
image
那么就进入下一个环节:LayoutInflater
又做了什么?
LayoutInflater
这个类是怎么把layout.xml
的<TextView>
变成TextView
对象的?