Skip to content

RrtoyewxXu/andSkin

Repository files navigation

andSkin

支持应用内部换肤和外部插件换肤,目前支持background,src,textColor等属性,支持状态栏,方便扩展。 关于换肤原理的相关介绍见 android 换肤

效果图

加载应用内的主题

加载应用外的主题

加载皮肤皮肤自动还原设置

优缺点

优点

  • 相比较多换肤的框架,并没有侵入View的生成过程,仅仅只是占用了LayoutInflaterFactory,如果在使用中需要LayoutInflaterFactory,可以借助LayoutInflater其他的Factory
  • 易于扩展,你只需要写下那个属性,另外在AttrFactory.java 注册即可
  • 初始化外部资源失败后,会进行自动切换资源加载,选择上一套或者默认
  • 能够选择是否开启更改状态栏的颜色
  • 支持动态加载的view
  • 更改起来方便,只需要在布局文件中的控件添加如下代码
skin:enable="true"

缺点或者说应该注意地方

在布局文件中,添加skin:enable="true"代码的控件必须申明具有id属性,否则不会更换

比如,对于下面两个控件,在换肤的时候并不会去更换资源的

<TextView
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:textColor="@color/text_color_main"
     skin:enable="true" />
<TextView
     android:id="@+id/tv_main_content"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:textColor="@color/text_color_main"/>

指定某个控件的单个/几个属性时,需要显示通过skin:attrs="src|background",默认不写的话,则按照attr支持所有的属性去检查,并生成相应属性对象,

比如对于ImageView,默认会生成src,background两个属性,即意味着,你在换肤的操作的时候,src和background各需要一套资源,即两者都需要更改,否则更换失败。

<ImageView
     android:id="@+id/iv_main_image"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="center_horizontal"
     android:background="@drawable/bg_image_selector"
     android:clickable="true"
     android:src="@drawable/bg_image_selector"
     skin:enable="true"/>

下面这种只会生成一个src的属性,即换肤的时候,仅仅只有src更换,background并不会更换

<ImageView
     android:id="@+id/iv_main_image"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="center_horizontal"
     android:background="@drawable/bg_image_selector"
     android:clickable="true"
     android:src="@drawable/bg_image_selector"
     skin:enable="true"
     skin:attrs="src"/>

同理,我们也可以设定background的属性,如下

<ImageView
     android:id="@+id/iv_main_image"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="center_horizontal"
     android:background="@drawable/bg_image_selector"
     android:clickable="true"
     android:src="@drawable/bg_image_selector"
     skin:enable="true"
     skin:attrs="background"/>

对于应用内部资源应该定义好后缀,并且应用内另一套资源名字为当前资源名字+后缀名字,而且要具有上述你所定义的所有要更换资源的资源文件。

例如,应用内部的默认名字为

    <color name="bg_main">#FFFFFF</color>
    <color name="text_color_main">#000000</color>
    <color name="status_bar_color">#000000</color>
    <color name="status_color">#000000</color>

则blue主题的资源文件为

    <color name="bg_main_blue">#444444</color>
    <color name="text_color_main_blue">#1111AA</color>
    <color name="status_bar_color_blue">#1111AA</color>
    <color name="status_color_blue">#0000FF</color>

注意,对于更换资源包里,必须要包含所有要更换的资源属性,比如,对于red主题来说,当加载red主题的时候,会失败,并且回退到上次的主题

    <color name="bg_main_red">#AAAAAA</color>
    <!--<color name="text_color_main_red">#AA2222</color>-->
    <color name="status_bar_color_red">#AA2222</color>
    <color name="status_color_red">#FF0000</color>

对于外部资源包的时候,可以定义的原来的名字,也可以像更换应用内资源一样定义好后缀名字

动态加载view

这里动态加载view,不只是addView的形式,而是在生成view的时候,比如listView的getView的方法,通常做法为

    if(contentView==null){
        contentView = LayoutInflater.from(context).inflate();
    }

这里通过inflat的时候加载view的时候,可以理解为广泛的动态加载view,类似的情况还有RecyclerView.onBindViewHolder以及Fragment.onCreateView等,这里需要将布局生成代码换成

convertView = baseSkinActivity.inflaterView(R.layout.item_main_list, parent, false);

内部实质是调用SkinLayoutInflater去解析xml布局可能存在需要更改的view

##如何使用

添加依赖

gradle

compile 'com.rrtoyewx.andskinlibrary:andskinlibrary:1.0.0'

maven

<dependency>
  <groupId>com.rrtoyewx.andskinlibrary</groupId>
  <artifactId>andskinlibrary</artifactId>
  <version>1.0.0</version>
  <type>pom</type>
</dependency>

2016.12.1 下午add to jcenter, 估计到2016.12.3 审核完

修改步骤

1.Application继承BaseSkinApplication 对于已经继承其他的Application,可以将BaseSkinApplication的相关代码复制到你的Application中

   beforeInit();
   SkinLoader.getDefault().init(this);
   afterInit();

2.Activity继承BaseSkinActivity

3.确认当前Activity是否需要更换皮肤,如果对于当前页面,没有需要更改换肤的控件的时候,可以选择重载shouldRegister()的方法,默认追踪当前的页面所有的资源。

    protected boolean shouldRegister() {
            return true;
    }

4.确定当前的Activity在换肤的操作过程,是否需要更改状态栏的颜色,如果想要关闭,则可以选择重载shouldChangeStatusBarColor(),默认打开。

    protected boolean shouldChangeStatusBarColor() {
            return true;
    }

5.更换资源

    //更换应用内部的资源
    SkinLoader.loadSkin(String resourceSuffix);
    //更换外部包的资源
    SkinLoader.loadSkin(String pluginAPKPackageName,String pluginAPKPath,String resourceSuffix)

6.注册监听,监听换肤操作是否成功

    SkinLoader.addOnChangeSkinListener(OnChangeSkinListener listener)

注册监听的对象会随着在注册监听时所处于页面的消失而被自动remove掉,这个是为了解决内存泄漏的问题

一些细节的说明

对于应用打开初始化的过程

对于页面注册流程图

对于应用启动后,点击换肤的流程图

说明

  1. restoreLastSkin或者restoreDefaultSkin都是一次loadSkin的过程
  2. DataManager保存信息成功或者失败,成功是代表上一次资源相关信息和本次换肤的资源相关信息不一样,则需要保存,即为成功。反之则为失败
  3. 生成Resource对象成功或者失败,成功是指加载外部插件成功生成相应的Resources对象。
  4. 因为采用的是才查找资源再更换的操作,所有在当所有资源都查找成功,才会进行回调,如果存在任一一个资源查找不到,也会认为失败,对于这一点,想了很久业务上面,避免了页面过度重绘
  5. 对于应用打开还原上次资源失败后采用的是还原默认皮肤,而对于应用正常启动,换肤操作失败还原上一次皮肤。

About

支持应用内部换肤和外部插件换肤,目前支持background,src,textColor等属性,方便扩展。

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages