ScoopsDemo
多主题风格代码demo
本文属代码GG原创,非经本人同意,禁止转载。
需要交流,联系微信:code_gg_boy
更多精彩,时时关注微信公众号code_gg_home
基本用法
- 简要说明
Scoops是一个android应用库,主要解决的是多主题实现方案。通过配置多个R.style.Theme ,代码进行动态设置主题,重启当前界面实现。
- 原理分析
主要通过设置主题(存储设置值), 重启activity,通过setTheme方式设置style实现。
- 使用方法
1项目的build.gradle里面
2 模块的build.gradle里面
3 values里面加入themes.xml
配置一些主题,为了多主题更换使用
4 AndroidManifest.xml里面
配置上默认主题,这里要注意的是配置的和5里面写的默认的那个要一致
5 MainApp里面
完成初始化,主要设置一系列的主题。其中addToppings为的是注释的时候使用,后面会讲它的用法。setSharedPreferences 配置默认的存储key值addDayNightFlavor 设置DayNight的主题风格,这个随后会讲到。
6 在MainAcitvity里面
1:需要继承AppCompatActivity
2:需要在setContentView前面调用Scoop.getInstance().apply(this);将主题设置进来。
3:这里说下为什么需要在AndroidManifest.xml里面配置默认主题,因为Scoops设计,在判断主题没有更改的情况下,不进行设置主题,因此第一次进来不会设置。所以我们要配置默认主题。并且和MainApp里面设置的默认值一样。
这里的true第三个参数说明设置为默认主题,和我们在AndroidManifest.xml设置的主题一致即可。
7 效果如下
8 代码地址
官网 地址 https://github.com/52inc/Scoops
demo地址 https://github.com/luxiaoming/ScoopsDemo
注解用法
- 简要说明
通过注释方式,完成多主题的效果更换。可以减少一些代码,使得代码更清晰一些。
- 使用说明
1 首先写一个注释类
2 在MainApp
初始化的时候,将注释通过addToppings方式设置进去
3 在MainActivity
使用注释@BindToppingStatus 标记下状态栏的颜色跟随
使用注释@BindTopping 标记下某个控件的颜色跟随
@BindTopping标记里面还可以有参数
1 value对应Toppings里面的某个值
2 adapter 跟上一个适配器,主要是为了实现某些控件自定义的设置颜色方案
3 interpolator 可以配置颜色切换过程效果,比如AccelerateInterpolator.class
代码可以看到还有一个注释,叫 @BindView(R.id.fab) 这个就是之前讲的Butter Knife ,不了解的可以在文章末尾看到地址
具体效果如下
4使用
在ButterKnife.bind(this);绑定了界面view后,使用 Scoop.sugarCone().bind(this);将view ,适配器和动画切换效果设置进来
在需要更新颜色的地方,使用Scoop.sugarCone().update即可,参数为第一个值为更新的注释类型,比如Toppings.PRIMARY_DARK参数二为颜色值。
5 ColorAdapter适配器
如果需要自己自定义主题更换后的view颜色变换动作(主要是有时候不符合我们的需求,比如我们想动态改文本颜色,高亮色等),我们就需要自定义一个实现ColorAdapter的类,比如ButtonColorAdapter接口 ColorAdapter定义了两个方法
设置新的颜色值
void applyColor(T view, @ColorInt int color);
获取当前颜色值
int getColor(T view);
6 主题bug
1 使用 @BindTopping 注释的时候,必须加上adapter=XXX.class 如果用默认的 ,请加上adapter = DefaultColorAdapter.class
2 默认的设置ScoopSettingsActivity界面,当设置为默认主题的时候,会出现bug。原因是这个界面指定了主题android:theme=”@style/Theme.AppCompat.Light” 如果我们默认的界面指定的跟这个不一样,则这个设置界面则会在默认主题的时候出错,和设置的效果不一致。解决方案:自己写一个设置界面呗。
7 demo地址
https://github.com/luxiaoming/ScoopsDemo
Butter Knife 注释编程阅读地址:
白天夜间主题
很多应用都有这个功能,可以选择白天和夜间模式,给用户更好的体验。为此,系统也提供了一种机制,来实现此功能。
模式主要分为四种 夜间 白天 跟随系统 和自动。具体实现可以去看com.android.support:appcompat-v7:23.0.0源码
夜间和白天模式很好理解。自动就是根据时间判断是否为白天和夜间,自动选择对应主题。跟随系统则使用系统的值,依赖系统。
实现原理
通过两组主题,分别放在values和values-night下面,系统根据你设置的模式,对应的去找主题配置值,然后设置上去即可。
使用说明
不使用Scoops方式
1自定义一个属性Attrs.xml
这里可以看到定义了两个属性textColor和textSize 格式分别为color和dimension
2创建一个目录values-night
3在values和values-night下面
新建一个文件themes.xml,同时配置相同的主题,加入我们自定义的属性textColor,给它配置值。
values下的属性
values-night下的属性
4使用的地方
这里mMode的值可以取以下几个
MODE_NIGHT_FOLLOW_SYSTEM
MODE_NIGHT_YES
MODE_NIGHT_NO
MODE_NIGHT_AUTO
5我们配置下使用的地方
这里的 android:textColor=”?attr/textColor” 记住用的是?attr来使用自定义的属性
6具体的结果,看Primary Color颜色变化
7代码地址
https://github.com/luxiaoming/ScoopsDemo
使用Scoops方式
1:MainApp
使用addDayNightFlavor将一个主题设置为DayNight模式
2:在对应的主题里面配置上文本颜色
values里面
values-night里面
3:进入app,在设置里面设置成dayNight模式后,点击按钮Scoops方式查看效果即可。
4:效果如下
5:代码地址
https://github.com/luxiaoming/ScoopsDemo
原理分析
核心代码位置
https://github.com/52inc/Scoops/tree/master/scoops/src/main/java/com/ftinc/scoop可以看到主要文件
Flavor.java 存储每个主题信息
Scoop.java 主文件,主要提供接口,作为对外调用。
SugarCone.java 解析注释的主文件,通过使用bind方法,去反射找到编译出来的Toppings类,通过这个来关联上来。
Topping.java 自定义注释方法。标记在属性上面,然后通过编译时候,使用插件scoops-compiler,生成后缀为Toppings的绑定类,随后我们使用bind函数,将这些类和界面关联起来。
关键方法
Scoop.apply函数
我们来看下public void apply(Activity activity)的具体代码流程找到当前的主题getCurrentFlavor
判断主题是否是白天夜间模式,如果是,设置模式然后使用
另一个apply方法,参数是activity和主题id设置主题,找到设置的背景色,设置窗体背景,然后返回去,我们自己recreate 重新启动当前界面,实现切换。
编译插件
https://github.com/52inc/Scoops/tree/master/scoops-compiler
主要目的是解析我们自定义的注解。解析的主要是我们在初始化时候使用addToppings加入的我们的注解。找到后,解析出来注解的标记值,切换过场特效,和适配器。标记值的目的是更新值的时候,用这个来做区分。
代码逻辑:找到所有的绑定在这个标记的view,然后逐个调用对应的适配器,进行对应的颜色更新。我们来看下核心的bind函数
我们看下bind 代码,主要看下getViewBinder这个方法即可。继续去看findViewBinderForClass 函数
代码主要流程为:从缓存能找到,直接返回。找不到,然后查找Class.forName(clsName + “_ToppingBinder”)类,构造一个,然后将这个返回,并缓存下来。然后调用里面的bind进行关联view我们反编译可以看到MainActivity_ToppingBinder.smali这个smali文件,这个就是插件生成出来的代码。我们反编译下,看下这个文件做了什么。
看到了吧,将注释的全部归类进来,为后面更新的时候查找使用。注释的原理就是如此了。