主流技术之网易云换肤方案

上一篇说到了View的加载过程,并且对TextView进行了拦截,让页面上所有的TextView内容都变成了我们想要的helloworld,这次我们一起来研究一下网易云音乐的动态换肤技术。说到换肤,有很多人选择了更改样式的方式,但是这种方式样式是固定的,必须提前内置好打包到apk中,所以导致apk包增大,并且灵活性不够强。今天我们要做的是打造一个动态下发+全属性修改+流畅无闪烁的换肤方案。要实现该方案主要有3个难点,分别是:如何批量修改View的背景、如何标识需要换肤的控件、如何加载插件皮肤资源到当前app中,接下来我们一个一个难题来攻破。


1.如何批量修改View的背景?

一个一个控件设置肯定是不现实的,这样会产生很多的垃圾代码,灵活性也不够强,所以必须想办法批量处理。这里可以通过view的hook技术,通过自定义Factory的方式来控制app中view的背景设置,从而实现不闪烁换肤的效果。既然我们拦截了系统生成view的过程,那么首先我们必须要自己生成view,不然页面就要空白了,生成view的具体代码如下:


这里调用mDelegate.createView是考虑到AppCompatActivity本身对一些控件做了一些兼容性问题,如果能在里面找到就直接使用就好了,如果没有找到的话,我们就要自己定义生成View的方式了。系统生成view时是使用反射的方式,这里我们也来模仿一下。需要用到反射的话就必须知道控件的包名,但是有些控件已经自带包名,比如V7下面的控件,这个时候我们通过判断这里是否包含"."来判断出来,然后直接把整个路径传进去就好了。包名的话主要是3种,如下:


具体生成的View方式和系统的一模一样,都是使用到反射来生成,这里再贴一下代码:


2.如何找到需要换肤的控件?

这里用的最多的方法是给控件设置一个属性来标记,判断哪个控件包含自定义的该属性,给包含的进行背景图片或颜色的替换。我们首先在values目录下新建一个attr.xml,然后在里面定义了一个叫做skinable的boolean属性,然后当该属性为true时就加入该控件到一个map中,准备进行换肤。其中attrs是前面初始化view时传过来的,代表该view的所有属性。判断出该控件需要换肤时,遍历出该控件所有属性加入到一个属性map中备用,具体代码如下:



3.如何实现资源的替换?

我们平时获取项目中的资源一般通过context.getResource().getXXX来获取,其实Resource只是一个皮包类,本质还是通过AssetManager来获取资源文件的,所以我们只需要获取到外部插件包的AssetManager对象即可,这里可以通过反射来获取到,并且调用addAssetPath方法来加载外部资源包。最后我们也将外部生成的AssetManager进行包一层Resource,为的是保留resid和资源的对应关系,这样才能实现资源的替换。


获取到了外部插件的Resource对象接下来就好办了,直接将当前app中控件的属性设置成外部的资源就大功告成了。这里attrsMap是我们自定义生成View时保存的某个View的所有属性,找出其中需要更换的属性,比如background、drawable什么的。



问题解答

1.如果同一控件不光要换背景,同时还要换字体怎么办?

答:这里可以再自定义一个属性代表字体需要替换

2.皮肤插件该怎么生成呢?

答:直接将当前项目更换一下资源文件,然后打包成apk,最后改个名字就好了,最好不要以apk结尾,以防用户去安装

3.现有app中的资源id是怎么和插件中的资源id进行对应的呢?

答:现有app中的Resource配置和插件Resource的配置是同一个,所以可以通过当前资源id=外部资源id的特殊性,根据当前资源id直接找到外部资源进行加载


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值