美文网首页
换肤方案

换肤方案

作者: AndroidHint | 来源:发表于2017-11-08 11:37 被阅读0次

背景需求

目前Android APP换肤大体可分为两大类:

  • 两套主题的切换(比如白天/黑夜),使用一个开关按钮进行切换。
  • 多套主题在线下载并更新。

第一种的实现基本上使用设置本地Theme来操作,即将所有的资源打包到APP中,并且根据主题进行切换。
第二种不可能使用第一种的实现方式,因为将所有资源都打包到APP中缺乏灵活性,不利于活动的更新,并且也会使得apk包的体积变大。所有第二种的实现必须是支持线上下载的。

方案选择

配合产品的需求并且能实现换肤的灵动性,我们选择上述的第二种方案。经过之前的Android和IOS成员小组讨论,统一觉得可以采用下载压缩包,并通过解析压缩包读取资源进行替换。

压缩包下载下来后怎么读取资源?这里有两种方式:

  • 将下载的皮肤包进行解压缩并且通过文件流的方式读取里面的图片资源、文件资源。
  • 将下载的皮肤包加载到assetManager管理器中,并通过该管理器新建一个Resource对象,需要换肤的控件通过Resource对象进行读取资源。

第一种方式需要手动开启文件流,并且不同的文件流有不同的文件流方式,比如图片、文本文件等,还有不同设备由于分辨率加载的资源是不同的,如何合理地去选择合适的资源去加载也是一个需要解决的问题。

第二种方式需要将皮肤包加载到assetManager管理器,assetManager管理器新生成的Resource对象和我们主工程的Resource对象是相同类的不同对象,可以使用我们熟悉的方式去加载资源(如resource.getColor,resource.getDrawable等)。

基于上述两种加载资源的方式,这里选择第二种方式进行资源的加载与读取。

具体实施

1、将所需的皮肤包通过网络下载到本地,这里的皮肤包是一个apk文件,为了让apk包足够小,里面只包含资源文件。可能有多个皮肤包,比如theme1.skin,theme2.skin......

2、通过后台获取需要加载的皮肤包的名字,如theme1.skin,通过调用AssetManager对象的addAssetPath方法并生成一个新的Resource对象,如下代码:

AssetManager assetManager = AssetManager.class.newInstance();
//由于addAssetPath()这个方法被隐藏掉了,所以不能直接使用对象直接访问,
//这里使用了反射的方式,作用是将该皮肤包加入到asset管理器中
Method addAssetPath = assetManager.getClass().getMethod("addAssetPath"
, String.class);
addAssetPath.invoke(assetManager, skinPath);

Resources skinResource = new Resources(
  assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());

3、自定义一个InflaterFactory的子类,SkinInflaterFactory,重写onCreateView(View, String, Context, AttributeSet) 方法,对于需要换肤的控件进行属性的解析与存储,然后对这些换肤的控件去第二步的Resource对象中加载资源并设置到这些控件中。

4、在BaseActivity的onCreate方法新建SkinInflaterFactory对象,并将该SkinInflateFactory对象设置给Activity的LayoutInflater对象,如下代码:

protected void onCreate(@Nullable Bundle savedInstanceState) {
    mSkinInflaterFactory = new SkinInflaterFactory();
    LayoutInflaterCompat.setFactory(
      getLayoutInflater(), mSkinInflaterFactory);
    super.onCreate(savedInstanceState);
}

流程图

换肤流程.png

其他问题

1、如何支持控件点击后触发不同的业务流程?
可以通过自定义一个属性,如skin:click="@string/clickAction",主工程的clickAction="muapp://app/testDefault",皮肤包里的clickAction="muapp://app/testClick",通过目前项目中的路由机制触发不同的跳转动作。比如说上述默认的跳转是跳转到主工程(app为module名)的TestDefaultAction(注解actionName="testDefault")类的invoke方法中,而更改后会跳转到主工程(app为module名)的TestClickAction(注解actionName="testClick")类的invoke方法中。

2、如何支持控件的不同行为方式?例如不同的动画效果等
这个问题和第一个问题的处理方式的类似的,同样可以通过主工程和皮肤包不同的tag(String文案)处理不同的行为方式。

3、如何处理自定义View的换肤需求?
可以添加一个方法,将自定义View需要换肤的属性名(如background),属性值(如background对应的图片的资源ID)传递到方法中,然后去皮肤包的Resource对象中寻找是否有相应的可替换的皮肤或者可替换的行为。

相关文章

  • 【靶点突破】网易云换肤方案探讨

    【靶点突破】网易云换肤方案探讨 老方案 网易云音乐换肤方案原理 动手实现一个网易云换肤方案的demo 动手打造换肤...

  • [Swift And OC] 聊一聊换肤方案

    [Swift And OC] 聊一聊换肤方案 [Swift And OC] 聊一聊换肤方案

  • Android Runtime Resource Overlay

    系统换肤方案来源于2014年sony在Android 5.0上针对定制化的Theme所提供的换肤方案,并且该方案被...

  • 换肤

    换肤 1. 换肤的应用场景? 2. 换肤的实现方案 方案1 1. 将图片以及颜色按照主题命名,使用虚拟文件夹, 直...

  • iOS换肤方案

    换肤方案在一些文艺App上经常见到。为新项目和老项目添加换肤方案查看原文

  • 换肤方案

    背景需求 目前Android APP换肤大体可分为两大类: 两套主题的切换(比如白天/黑夜),使用一个开关按钮进行...

  • 再谈APP换肤实现

    导语:此前发表的关于APP换肤实现原理的文章——《APP动态换肤方案详解[https://www.jianshu....

  • 一文总结前端换肤换主题

    最近项目涉及换主题/换肤的工作, 查了查资料,总结出五种换肤方案: 这是五种均为通用方案,可以适用于各种前端框架,...

  • 换肤方案一: scss换肤

    1. 效果图 2. 实现原理 添加全局样式,动态改变主题 通过scss 定义多套主题 使用混合模式动态取值 3. ...

  • Android换肤方案

    换肤方案:(1)内部资源加载方案:定义几套主题,所有的图片,背景等资源都打包到apk里面,通过BaseActivi...

网友评论

      本文标题:换肤方案

      本文链接:https://www.haomeiwen.com/subject/enosmxtx.html