0%

Android插件化动态换肤


动态换肤算是APP开发中常见的技术,最近公司的项目也是正好用到,需求是从后台下载皮肤包到本地,用户可以选择自己喜欢的皮肤包进行页面的动态换肤,增强用户体验和应用的趣味性。大致整理了一下实现思路,在此做个记录,如果有更好的方案,欢迎交流~

  1. 读取apk的内容
    异步加载本地目录的皮肤资源apk,通过反射调用AssetManager添加资源路径的方法将apk的资源加载进去,得到全新的AssetManager并注册,加载资源时使用新AssetManager的资源,新resource赋给全局的resource,切回默认app皮肤时,再赋值回默认的resource。
  2. 收集换肤的View相关数据,干预xml解析拦截需要换肤的view,Factory2中生产view时记录需要换肤的属性
  3. 观察者模式绑定被观察者-资源管理器和观察者-自定义的LayoutInflater.Factory2,BaseActivity实现统一换肤接口ISkinUpdate的逻辑调资源管理器加载皮肤APK。
  4. 执行换肤逻辑
    设置自定义的LayoutInflater.Factory2,拦截xml中原本解析的view返回一个新的view,判断当前view是否需要换肤,需要则直接设置相应属性,不需要则执行原本逻辑。

皮肤管理器

在Application中初始化皮肤管理器,继承Observable类,是一个可被观察的对象,需要通知观察者对象,主要负责加载本地皮肤包apk并更新皮肤resource对象到资源管理器,通知各个需要换肤的View更新UI,并记录当前使用的皮肤包路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public class SkinManager extends Observable {

private volatile static SkinManager instance;
/**
* Activity生命周期回调
*/
private ApplicationActivityLifecycle skinActivityLifecycle;
private Application mContext;

/**
* 初始化 必须在Application中先进行初始化
*
* @param application
*/
public static void init(Application application) {
if (instance == null) {
synchronized (SkinManager.class) {
if (instance == null) {
instance = new SkinManager(application);
}
}
}
}

private SkinManager(Application application) {
mContext = application;
//初始化sp,记录当前使用的皮肤
SkinPreference.init(application);
//资源管理类,从皮肤resource对象中加载资源
SkinResources.init(application);
//注册Activity生命周期,并设置被观察者
skinActivityLifecycle = new ApplicationActivityLifecycle(this);
application.registerActivityLifecycleCallbacks(skinActivityLifecycle);
//加载上次使用保存的皮肤
loadSkin(SkinPreference.getInstance().getSkin());
}

public static SkinManager getInstance() {
return instance;
}


/**
* 加载皮肤并更新resource到皮肤资源管理器
*
* @param skinPath 皮肤路径 如果为空则使用默认皮肤
*/
public void loadSkin(String skinPath) {
if (TextUtils.isEmpty(skinPath)) {
//还原默认皮肤
SkinPreference.getInstance().reset();
SkinResources.getInstance().reset();
} else {
try {
//宿主app的resources;
Resources appResource = mContext.getResources();
//反射创建AssetManager与Resource
AssetManager assetManager = AssetManager.class.newInstance();
//资源路径设置,压缩包的目录
Method addAssetPath = assetManager.getClass().getMethod("addAssetPath",
String.class);
addAssetPath.invoke(assetManager, skinPath);

//根据设备显示器信息与配置(横竖屏、语言等)创建新的皮肤Resources
Resources skinResource = new Resources(assetManager, appResource.getDisplayMetrics
(), appResource.getConfiguration());

//获取本地皮肤Apk(皮肤包) 包名,并应用皮肤
PackageManager mPm = mContext.getPackageManager();
PackageInfo info = mPm.getPackageArchiveInfo(skinPath, PackageManager
.GET_ACTIVITIES);
String packageName = info.packageName;
SkinResources.getInstance().applySkin(skinResource, packageName);

//记录当前使用的皮肤路径
SkinPreference.getInstance().setSkin(skinPath);


} catch (Exception e) {
e.printStackTrace();
}
}
//通知采集的View 更新皮肤
//被观察者改变,通知所有观察者
setChanged();
notifyObservers(null);
}

}
  • SP工具类,记录皮肤包路径
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    public class SkinPreference {
    private static final String SKIN_SHARED = "skins";
    private static final String KEY_SKIN_PATH = "skin-path";
    private volatile static SkinPreference instance;
    private final SharedPreferences mPref;

    public static void init(Context context) {
    if (instance == null) {
    synchronized (SkinPreference.class) {
    if (instance == null) {
    instance = new SkinPreference(context.getApplicationContext());
    }
    }
    }
    }

    public static SkinPreference getInstance() {
    return instance;
    }

    private SkinPreference(Context context) {
    mPref = context.getSharedPreferences(SKIN_SHARED, Context.MODE_PRIVATE);
    }

    public void setSkin(String skinPath) {
    mPref.edit().putString(KEY_SKIN_PATH, skinPath).apply();
    }

    public void reset() {
    mPref.edit().remove(KEY_SKIN_PATH).apply();
    }

    public String getSkin() {
    return mPref.getString(KEY_SKIN_PATH, null);
    }

    }

    监听Activity生命周期

    传入被观察者-皮肤管理器对象,缓存activity到对应自定义LayoutInflaterFactory对象的映射
  1. Activity被创建时,反射设置mFactorySet属性为false,设置自定义的LayoutInflaterFactory,并记录与当前activity的映射关系到map,添加自定义的LayoutInflaterFactory对象为皮肤管理器对象的观察者对象,接收皮肤管理器加载完成的通知
  2. Activity被销毁时,获取到对应的自定义LayoutInflaterFactory对象,移除对被观察者-皮肤管理器对象的监听
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    public class ApplicationActivityLifecycle implements Application.ActivityLifecycleCallbacks {

    private Observable mObserable; // 被观察者,皮肤管理器对象
    private ArrayMap<Activity, SkinLayoutInflaterFactory> mLayoutInflaterFactories = new
    ArrayMap<>(); // 记录activity到对应自定义LayoutInflaterFactory对象的映射

    public ApplicationActivityLifecycle(Observable observable) {
    mObserable = observable;
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    /**
    * 更新状态栏
    */
    SkinThemeUtils.updateStatusBarColor(activity);

    /**
    * 更新布局视图
    */
    //获得Activity的布局加载器
    LayoutInflater layoutInflater = activity.getLayoutInflater();

    try {
    //Android 布局加载器 使用 mFactorySet 标记是否设置过Factory
    //反射设置 mFactorySet 标签为false
    Field field = LayoutInflater.class.getDeclaredField("mFactorySet");
    field.setAccessible(true);
    field.setBoolean(layoutInflater, false);
    } catch (Exception e) {
    e.printStackTrace();
    }

    //设置自定义的LayoutInflaterFactory,并记录与当前activity的映射关系到map
    SkinLayoutInflaterFactory skinLayoutInflaterFactory = new SkinLayoutInflaterFactory
    (activity);
    LayoutInflaterCompat.setFactory2(layoutInflater, skinLayoutInflaterFactory);
    mLayoutInflaterFactories.put(activity, skinLayoutInflaterFactory);

    mObserable.addObserver(skinLayoutInflaterFactory);
    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    @Override
    public void onActivityResumed(Activity activity) {

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {
    SkinLayoutInflaterFactory observer = mLayoutInflaterFactories.remove(activity);
    SkinManager.getInstance().deleteObserver(observer);
    }
    }

    皮肤资源管理器

    记录原始宿主App的resource对象和新的皮肤resource对象,从皮肤resource对象中获取对应的属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    public class SkinResources {

    private String mSkinPkgName;
    private boolean isDefaultSkin = true;

    // app原始的resource
    private Resources mAppResources;
    // 皮肤包的resource
    private Resources mSkinResources;

    private SkinResources(Context context) {
    mAppResources = context.getResources();
    }

    private volatile static SkinResources instance;
    public static void init(Context context) {
    if (instance == null) {
    synchronized (SkinResources.class) {
    if (instance == null) {
    instance = new SkinResources(context);
    }
    }
    }
    }

    public static SkinResources getInstance() {
    return instance;
    }

    public void reset() {
    mSkinResources = null;
    mSkinPkgName = "";
    isDefaultSkin = true;
    }

    public void applySkin(Resources resources, String pkgName) {
    mSkinResources = resources;
    mSkinPkgName = pkgName;
    //是否使用默认皮肤
    isDefaultSkin = TextUtils.isEmpty(pkgName) || resources == null;
    }

    /**
    * 1.通过原始app中的resId(R.color.XX)获取到自己的 名字
    * 2.根据名字和类型获取皮肤包中的ID
    */
    public int getIdentifier(int resId){
    if(isDefaultSkin){
    return resId;
    }
    String resName=mAppResources.getResourceEntryName(resId);
    String resType=mAppResources.getResourceTypeName(resId);
    int skinId=mSkinResources.getIdentifier(resName,resType,mSkinPkgName);
    return skinId;
    }

    /**
    * 输入主APP的ID,到皮肤APK文件中去找到对应ID的颜色值
    * @param resId
    * @return
    */
    public int getColor(int resId){
    if(isDefaultSkin){
    return mAppResources.getColor(resId);
    }
    int skinId=getIdentifier(resId);
    if(skinId==0){
    return mAppResources.getColor(resId);
    }
    return mSkinResources.getColor(skinId);
    }

    public ColorStateList getColorStateList(int resId) {
    if (isDefaultSkin) {
    return mAppResources.getColorStateList(resId);
    }
    int skinId = getIdentifier(resId);
    if (skinId == 0) {
    return mAppResources.getColorStateList(resId);
    }
    return mSkinResources.getColorStateList(skinId);
    }

    public Drawable getDrawable(int resId) {
    if (isDefaultSkin) {
    return mAppResources.getDrawable(resId);
    }
    //通过 app的resource 获取id 对应的 资源名 与 资源类型
    //找到 皮肤包 匹配 的 资源名资源类型 的 皮肤包的 资源 ID
    int skinId = getIdentifier(resId);
    if (skinId == 0) {
    return mAppResources.getDrawable(resId);
    }
    return mSkinResources.getDrawable(skinId);
    }


    /**
    * 可能是Color 也可能是drawable
    *
    * @return
    */
    public Object getBackground(int resId) {
    String resourceTypeName = mAppResources.getResourceTypeName(resId);

    if ("color".equals(resourceTypeName)) {
    return getColor(resId);
    } else {
    // drawable
    return getDrawable(resId);
    }
    }

    }

    自定义LayoutInflatorFactory

  3. 自定义LayoutInflatorFactory继承LayoutInflater.Factory2和Observer,是一个观察者对象,需要对皮肤管理器对象进行监听,接收到通知时应用皮肤,刷新状态栏,所有需要换肤的View刷新UI
  4. 解析xml创建View时,如果不是SDK自带的view就反射创建,如果是SDK的view尝试增加固定前缀,再反射创建,再修改View的属性刷新UI,达到换肤的效果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    public class SkinLayoutInflaterFactory implements LayoutInflater.Factory2, Observer {
    // 待尝试的系统view固定前缀
    private static final String[] mClassPrefixList = {
    "android.widget.",
    "android.webkit.",
    "android.app.",
    "android.view."
    };


    private static final Class<?>[] mConstructorSignature = new Class[] {
    Context.class, AttributeSet.class};
    // 记录view名称与对应构造函数的映射
    private static final HashMap<String, Constructor<? extends View>> mConstructorMap =
    new HashMap<String, Constructor<? extends View>>();

    // 当选择新皮肤后需要替换View与之对应的属性
    // Activity的属性管理器
    private SkinAttribute skinAttribute;
    // 用于获取窗口的状态栏
    private Activity activity;

    // 初始化属性管理器
    public SkinLayoutInflaterFactory(Activity activity) {
    this.activity = activity;
    skinAttribute = new SkinAttribute();
    }

    @Override
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
    //换肤就是替换View的属性(src、background等)
    //创建 View,再修改View属性
    View view = createSDKView(name, context, attrs);
    if (null == view) {
    view = createView(name, context, attrs);
    }

    if (null != view) {
    //加载属性
    skinAttribute.look(view, attrs);
    }
    return view;
    }


    private View createSDKView(String name, Context context, AttributeSet
    attrs) {
    //如果包含 . 则不是SDK中的view,可能是自定义view包括support库中的View,尝试使用后面的构造方法反射创建
    if (-1 != name.indexOf('.')) {
    return null;
    }
    //不包含,是SDK中的view,在解析的name节点前,拼接上一些前缀如:android.widget. 尝试反射创建View
    for (int i = 0; i < mClassPrefixList.length; i++) {
    View view = createView(mClassPrefixList[i] + name, context, attrs);
    if(view!=null){
    return view;
    }
    }
    return null;
    }

    // 反射创建View
    private View createView(String name, Context context, AttributeSet
    attrs) {
    Constructor<? extends View> constructor = findConstructor(context, name);
    try {
    return constructor.newInstance(context, attrs);
    } catch (Exception e) {
    }
    return null;
    }

    private Constructor<? extends View> findConstructor(Context context, String name) {
    Constructor<? extends View> constructor = mConstructorMap.get(name);
    if (constructor == null) {
    try {
    Class<? extends View> clazz = context.getClassLoader().loadClass
    (name).asSubclass(View.class);
    constructor = clazz.getConstructor(mConstructorSignature);
    mConstructorMap.put(name, constructor);
    } catch (Exception e) {
    }
    }
    return constructor;
    }

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
    return null;
    }

    //如果有人发送通知,这里就会执行
    @Override
    public void update(Observable o, Object arg) {
    SkinThemeUtils.updateStatusBarColor(activity);
    skinAttribute.applySkin();
    }
    }

    属性管理器

    记录所有View需要替换的属性名称,需要换肤的View与View的属性信息列表,遍历当前解析的View的所有属性,过滤该View需要替换的属性并记录,对需要换肤的View进行属性修改
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    public class SkinAttribute {
    private static final List<String> mAttributes = new ArrayList<>();
    // 需要替换的属性名称
    static {
    mAttributes.add("background");
    mAttributes.add("src");
    mAttributes.add("textColor");
    mAttributes.add("drawableLeft");
    mAttributes.add("drawableTop");
    mAttributes.add("drawableRight");
    mAttributes.add("drawableBottom");
    }

    //记录需要换肤的View与View的属性信息
    private List<SkinView> mSkinViews = new ArrayList<>();


    // 遍历当前View的属性,记录需要替换的属性并执行换肤,对View进行属性修改
    public void look(View view, AttributeSet attrs) {
    List<SkinPair> mSkinPars = new ArrayList<>();

    for (int i = 0; i < attrs.getAttributeCount(); i++) {
    // 获得属性名如textColor/background
    String attributeName = attrs.getAttributeName(i);
    // 如果这个属性是需要替换的属性
    if (mAttributes.contains(attributeName)) {
    // 比如color的值有多种格式
    // #
    // ?722727272
    // @722727272
    // 以#开头表示写死的颜色 不可用于换肤
    String attributeValue = attrs.getAttributeValue(i);
    if (attributeValue.startsWith("#")) {
    continue;
    }
    int resId;
    // 以?开头的,去主题资源中找属性值
    if (attributeValue.startsWith("?")) {
    int attrId = Integer.parseInt(attributeValue.substring(1));
    resId = SkinThemeUtils.getResId(view.getContext(), new int[]{attrId})[0];
    } else {
    // 正常以 @ 开头
    resId = Integer.parseInt(attributeValue.substring(1));
    }
    // 记录到当前View需要替换的属性表
    SkinPair skinPair = new SkinPair(attributeName, resId);
    mSkinPars.add(skinPair);
    }
    }
    // 如果当前view有属性需要替换,或者该属性是支持换肤的自定义view
    if (!mSkinPars.isEmpty() || view instanceof SkinViewSupport) {
    SkinView skinView = new SkinView(view, mSkinPars);
    // 执行换肤,进行View的属性修改
    skinView.applySkin();
    // 添加到缓存
    mSkinViews.add(skinView);
    }
    }


    /*
    对所有需要换肤的view执行换肤操作
    */
    public void applySkin() {
    for (SkinView mSkinView : mSkinViews) {
    mSkinView.applySkin();
    }
    }

    static class SkinView {
    View view;
    // 当前View需要替换的属性列表
    List<SkinPair> skinPairs;

    public SkinView(View view, List<SkinPair> skinPairs) {
    this.view = view;
    this.skinPairs = skinPairs;

    }
    /**
    * 对一个View中所有需要替换的属性进行修改
    */
    public void applySkin() {
    // 如果是支持换肤的自定义view调换肤接口
    applySkinSupport();
    // 遍历当前View需要替换的属性列表
    for (SkinPair skinPair : skinPairs) {
    Drawable left = null, top = null, right = null, bottom = null;
    switch (skinPair.attributeName) {
    case "background":
    Object background = SkinResources.getInstance().getBackground(skinPair
    .resId);
    //背景可能是 @color 也可能是 @drawable
    if (background instanceof Integer) {
    view.setBackgroundColor((int) background);
    } else {
    ViewCompat.setBackground(view, (Drawable) background);
    }
    break;
    case "src":
    background = SkinResources.getInstance().getBackground(skinPair
    .resId);
    if (background instanceof Integer) {
    ((ImageView) view).setImageDrawable(new ColorDrawable((Integer)
    background));
    } else {
    ((ImageView) view).setImageDrawable((Drawable) background);
    }
    break;
    case "textColor":
    ((TextView) view).setTextColor(SkinResources.getInstance().getColorStateList
    (skinPair.resId));
    break;
    case "drawableLeft":
    left = SkinResources.getInstance().getDrawable(skinPair.resId);
    break;
    case "drawableTop":
    top = SkinResources.getInstance().getDrawable(skinPair.resId);
    break;
    case "drawableRight":
    right = SkinResources.getInstance().getDrawable(skinPair.resId);
    break;
    case "drawableBottom":
    bottom = SkinResources.getInstance().getDrawable(skinPair.resId);
    break;
    default:
    break;
    }
    if (null != left || null != right || null != top || null != bottom) {
    ((TextView) view).setCompoundDrawablesWithIntrinsicBounds(left, top, right,
    bottom);
    }
    }
    }
    private void applySkinSupport() {
    if (view instanceof SkinViewSupport) {
    ((SkinViewSupport) view).applySkin();
    }
    }
    }

    static class SkinPair {
    //属性名
    String attributeName;
    //对应的资源id
    int resId;

    public SkinPair(String attributeName, int resId) {
    this.attributeName = attributeName;
    this.resId = resId;
    }
    }
    }

主题工具类

负责根据属性id获得theme中对应资源id的值,刷新状态栏颜色为皮肤包中定义的颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class SkinThemeUtils {

private static int[] APPCOMPAT_COLOR_PRIMARY_DARK_ATTRS = {
android.support.v7.appcompat.R.attr.colorPrimaryDark
};
private static int[] STATUSBAR_COLOR_ATTRS = {android.R.attr.statusBarColor, android.R.attr
.navigationBarColor
};


/**
* 获得theme中的属性中定义的 资源id
* @param context
* @param attrs
* @return
*/
public static int[] getResId(Context context, int[] attrs) {
int[] resIds = new int[attrs.length];
TypedArray a = context.obtainStyledAttributes(attrs);
for (int i = 0; i < attrs.length; i++) {
resIds[i] = a.getResourceId(i, 0);
}
a.recycle();
return resIds;
}



public static void updateStatusBarColor(Activity activity) {
//5.0以上才能修改
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return;
}
//获得 statusBarColor 与 nanavigationBarColor (状态栏颜色)
//当与 colorPrimaryDark 不同时 以statusBarColor为准
int[] resIds = getResId(activity, STATUSBAR_COLOR_ATTRS);
int statusBarColorResId = resIds[0];
int navigationBarColor = resIds[1];

//如果获取到状态栏颜色资源id,那么设置状态栏颜色
if (statusBarColorResId != 0) {
int color = SkinResources.getInstance().getColor(statusBarColorResId);
activity.getWindow().setStatusBarColor(color);
} else {
//获得主色资源id
int colorPrimaryDarkResId = getResId(activity, APPCOMPAT_COLOR_PRIMARY_DARK_ATTRS)[0];
// 如果获取到主色资源id,那么设置状态栏颜色
if (colorPrimaryDarkResId != 0) {
int color = SkinResources.getInstance().getColor(colorPrimaryDarkResId);
activity.getWindow().setStatusBarColor(color);
}
}
// 如果获取到导航栏资源id,那么设置导航栏颜色
if (navigationBarColor != 0) {
int color = SkinResources.getInstance().getColor
(navigationBarColor);
activity.getWindow().setNavigationBarColor(color);

}
}

}