前言
最近有个换肤的需求。基于github上的这个开源框架Android-Skin-Loader。这个框架的换肤机制是使用动态加载的机制去加载皮肤包里面的内容,所谓的皮肤包是实际上是一个apk文件,里面无需任何java代码。只要把和需要换肤的apk相同文件名的资源文件添加到res文件夹底下即可。(后面会针对怎么制作皮肤包做一个详解)
本文提供了源代码的下载,对急于想使用干货的童鞋很有帮助,只要认真看完肯定就能上手。
对于这个框架的源码分析暂不做研究,感兴趣的童鞋前往此处 Android主题换肤 无缝切换。同时也感谢作者的资源分享!
好了,废话不多bb。现在我们开始研究如何使用干货。
1 下载基本的android-skin-loader的文件
百度网盘 提取码: dbje
同时也欢迎下载自己的github开源项目,里面包含了换肤等其他效果 。
2Application继承SkinBaseApplication
3对需要使用的view添加标志
有两种方式 1)在xml文件中添加 skin:enable="true"
2)那么有的人会有一个疑问,如果我的view是动态添加的呢?别急,作者也想到了这个需求,我们也可以动态的添加标识。
我们看下这个方法
第一个参数:需要换肤的view、第二个参数:类型名、第三个参数是资源文件id
主要是第二个参数:类型名
实际上这个是可以自定义的,关于自定义皮肤属性下面会讲。
4使用换肤功能的activity继承SkinBaseActivity
当然如果是fragment就继承SkinBaseFragment
5换肤
我们可以看到真正使用的是load方法,第一个参数是资源路径,第二个参数是回调。
可以看到这里做的是本地资源保存然后我将他写入了根目录下。当然这里使用线上下载也是同样的道理,相信不是什么问题。只是这里为了方便所以用了本地的,建议换肤前先下载 xxxx.skin文件到手机外存储。
好了,大概的使用就这样。
付加:
1此处我们对上文提到的自定义皮肤属性进行研究。
其中我们看到既然有background那么我们是否可以对ImageView设置前景图片src呢? 答案是肯定的。
我们模仿他写了一个SRC=“src".
调用get的方法
注意条件 AttfFactory.isSuppotesAttr(attrName) 这句话从字面上可以知道是匹配属性名是否支持提供的几个皮肤属性。如果匹配比如:src则返回SrcAttr。
SrcAttr 这个类是我们自定义的我们接下去看
自定义皮肤属性总结:
原理还需要看源码,上面的几张图的代码是主要所在。
如果只看功能的实现:首先要自定义一个类继承SkinAttr 如上图。接着在AttrFactory的get方法中添加返回。
需要注意的是比如我的imageview设置src,一定要加上skin:eanble="true"或者动态添加。理由如下:
如上图可看出在返回view之前做了一步筛选,如果没有设置enable则直接过滤。
2 皮肤文件的制作
皮肤文件实际上是一个只包含了资源文件不需java代码的pak文件
1首先创建一个新的project将和需要换肤的原apk中同名的资源文件导入。比如原apk中有一个需要换肤的textview字体颜色是@color/white 那么新的project一定要存在一个同名的资源文件至于颜色那就根据实际重新设置了。
2导出project的apk文件 改名为xxxx.skin
3将xxxx.skin文件写入本地作为本地换肤或者扔给服务器让他们提供一个地址下载到本地作为线上换肤,如果修改文件大的话肯定是建议后者。
bug:
目前发现的bug不多
1: 如果你的应用是全屏的,当发现在application初始化换肤设置(也就是换肤可以实行的操作)就会发现出现状态而导致无法全屏
解决方法: 代码研究后发现在SkinBaseActivity中有个changeStatusColor(),系统默认4.4以上都会修改状态栏的颜色。于是把他注释掉就可以实现全屏的需求了。
2:细心的童鞋其实还会发现一个问题,比如我一个ImageView背景是根据条件的设置的比如条件1: 背景R.drawable.icon1 条件2:背景是R.drawable.icon2那现在就有一个问题了。上文提到的皮肤包设置的资源文件名字必须和原始的一样,那这种情况我要怎么设置名字呢?
解决方法: 实际上上文也提过一个动态添加皮肤view的方式。凡是类似这种需求的都用动态添加的方式
dynamicAddSkinEnableView(View view,String attrName, intattrValueResId)
该方法包括了动态添加修改标志以及设置了设置了资源,所以无需重新设置背景或者颜色。
另外
SkinManager.getInstance.notifySkinUpdate();耗时操作,记得一定要慎用!