Android UIAndroid项目源码三方架构分析

Android换肤方案总结

2018-07-23  本文已影响136人  zizi192

这篇总结也是拖了很久了,欠下的技术债必须得偿还啦~

Android换肤在使用场景上可以区分为静态换肤/动态换肤、应用内换肤/插件式换肤。不同的换肤方案,适用于不同的业务场景。

setTheme可以较好的支持静态换肤,但如果要动态换肤则需要解决的核心问题有:

第一个资源加载的问题可以通过构造AssetManager,反射调用其addAssetPath就可以完成。
第二个问题,就可以利用在onCreateView中,根据view的属性来定位。应用内换肤一般以资源前缀或后缀来区分不同资源,辅助以tag或侵入式等来区分换肤的view;进而保存需要换肤的view引用。

在个人的应用场景中,需要支持动态实时换肤,且以应用内换肤为主。最终在开源框架ChangeSkin的基础上进行了改造来满足需求。

下面会介绍不同的换肤方案及优缺点。

切换Theme

首先,在attr.xml中定义支持换肤的属性。一般是textColor,background等。如果系统支持的字体颜色,背景色较多,则需要增加很多的自定义属性。

<resources>
    <attr name="textColor" format="reference|color"/>
    <attr name="background" format="reference|color"/>
</resources>

其次,在不同主题的style中定义属性值。

<style name="AppTheme_Light" >
    <item name="textColor">@android:color/black</ item>
    <item name="android:background">@android:color/white</ item>
</style>
 
<style name="AppTheme_Night">
    <item name="textColor">@android:color/white</ item>
    <item name="android:background">@android:color/black</ item>
</style>

再次,View上应用style(?attr/nbackground表示使用style内的此属性作为view 的background).

<TextView
    android :id="@+id/textview"
    android :layout_width="wrap_content"
    android :layout_height="wrap_content"
    android :text="Hello World!"
    android :background="?attr/background"
    android :textColor="?attr/textColor"/>

最后,在Java代码内根据情况设置主题并刷新界面。如果要支持动态换肤,则必须要设置换肤的监听,全部页面实现一个回调。原因是setTheme方法要在setContentView之前调用才能生效。

//设置换肤回调
@Override
protected void onSkinChange() {
    TypedValue background = new TypedValue();
    TypedValue textColor = new TypedValue();
    Resources.Theme theme = getTheme();
    theme.resolveAttribute(R.attr.background, background, true);
    theme.resolveAttribute(R.attr.textColor, textColor, true);
    mTextView .setTextColor(textColor.data);
    mTextView.setBackgroundResource(background.resourceId);
    
    ...
}

方案优点:

方案缺点:

换肤框架AndroidChangeSkin

项目地址:https://github.com/hongyangAndroid/AndroidChangeSkin
该框架通过相同名称+不同皮肤后缀来区分不同皮肤,再通过View的Tag来标志夜间模式的Drawable/Color引用。
如实现黑白皮肤,文本颜色item_text_color有一套默认皮肤,一套黑色皮肤定义资源item_text_color,item_text_color_black。
方案优点:

方案缺点:

<TextView
    android :layout_width="wrap_content"
    android :layout_height="wrap_content"
    android :tag="skin:item_text_color:textColor"
    android :text="@string/hello_world"
    android :textColor="@color/item_text_color"/>

换肤框架ChangeSkin

项目地址:https://github.com/hongyangAndroid/ChangeSkin.
针对框架AndroidChangeSkin需要为每个支持换肤的view设置tag,鸿洋实现了侵入式换肤的方案。该框架也参考了AndroidSkinLoader。
该框架最主要的方法在于baseSkinactivity中,侵入了onCreateView方法,使用了视图兼容工厂。遍历反射创建的view,根据资源前缀来标志是否支持换肤,存储支持换肤的view引用,以实现动态换肤。

在应用的某些场景,需要动态获取当前皮肤某资源信息,如黑白皮肤的主题颜色,需要通过SkinManager获取ResourceManager对象,进而通过Resources的getColor方法获取颜色值。参数为资源名,为了便于开发,可通过getResourceName将resId转化为resName。

public static int getSkinColor(@ColorRes int resId){
        if (SkinManager.getInstance().isUseSkinPlugin()) {
            String resName = CoreApplication.getInstance().getResources().getResourceName(resId);
            return SkinManager.getInstance().getResourceManager().getColor(resName);
        }

        int retColor = CoreApplication.getInstance().getResources().getColor(resId);
        return retColor;
    }

方案优点:

方案缺点:

换肤框架AndroidSkinLoader

该方案为侵入式方案,通过为LayoutInfalter去设置自定义Factory,对加载的View进行分析和提取。

具体可参考项目地址:https://github.com/fengjundev/Android-Skin-Loader

参考文章:
android 换肤(1)——插件式无缝换肤(解析鸿洋大神的换肤流程)
android 换肤(2)——插件式无缝换肤(解析鸿洋大神的换肤流程)
Android换肤技术总结
Android夜间模式调研总结

上一篇 下一篇

猜你喜欢

热点阅读