Android Theme主题样式一键换肤
2017-10-31 10:55
381 查看
前言:之前看过网易云音乐换肤的demo,是一个开源项目,实现方法大概是添加Gradle依赖后,再创建一个拥有不同图片和主题风格的项目子模块,然后切换所谓的主题切换,就能够根据不同的方法设定,呈现不同风格的界面给用户,也就是所谓的换肤。 其实谷歌v7后的主题Theme其实就有意给开发者们开辟换肤的功能。接来下,我们一起手动制作一款可以换肤主题,开始撸码吧!
2
3
4
5
6
7
attr里可以定义属性类型:如color、float、integer、boolean、dimension(sp、dp/dip、px、pt…)、reference(指向本地资源)等等。
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
2
3
4
5
6
7
8
9
10
11
这里只列出了颜色的例子android:background=”?attr/mainColor” ;
还可以使用“?attr/colorValue”、“?attr/stringValue”、“?attr/referenceValue”来引用主题中的颜色值、字符串以及图片。
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
要在Activity的onCreate方法里的setContextView前使用了。这里最好写在BaseActivity中,更具share保存的样式值,来动态设置theme。
《方法1 》:自定义需要样式变换的所有View,
为了不重启activity, 自定义了所有需要样式变动的View, 原理为通过对rootView进行遍历,对所有实现了ColorUiInterface的view/viewgroup进行setTheme操作来实现即使刷新的。方式臃肿粗暴, 虽然是不需要重启activity,还可以针对每个view变换过程做动画,但是个人不推荐.
《方法2》:动态获取需要变更的控件,获取atts值,对每一个控件进行操作,也不需要重启Activity,但是有点繁琐。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
《方法3》乖乖的遵循重启Activity。为了美化转变效果,可以正对activity做一些动画,效果也是不错,看效果图:
2
3
《方法2》
2
3
APK主题方案和主题包保存到SD卡上(墨迹,搜狗实现方式)的方案类似,只不过是apk压缩格式,一些资源的引用可以调用系统api。
APK主题方案的基本思路是:在Android中,所有的资源都是基于包的。资源以id进行标识,在同一个应用中,每个资源都有唯一标识。但在不同的应用中,可以有相同的id。因此,只要获取到了其他应用的Context对象,就可以通过它的getRsources获取到其绑定的资源对象。然后,就可以使用Resources的getXXX方法获取字符串、颜色、dimension、图片等。
要想获取其他应用的Context对象,Android已经为我们提供好了接口。那就是android.content.ContextWrapper.createPackageContext(String packageName, int flags)方法。
2
3
4
5
6
7
8
9
10
11
除了压缩包,apk包等实现方式,还可以考虑插件实现方式,目的都是更好的解耦,更方便的迭代项目.
【one】第一步,统一自定义属性名,attr.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="mainColor" format="color" /> <attr name="mainPrimaryTextColor" format="color" /> <attr name="mainPrimaryLightTextColor" format="color" /> <attr name="mainBgColor" format="color" /> </resources>1
2
3
4
5
6
7
attr里可以定义属性类型:如color、float、integer、boolean、dimension(sp、dp/dip、px、pt…)、reference(指向本地资源)等等。
【two】第二步,在Value文件中自定义若干套主题Style:
<style name="AppTheme.Base.Green"> <item name="colorPrimary">#4CAF50</item> <item name="colorPrimaryDark">#388E3C</item> <item name="colorAccent">#9E9E9E</item> <item name="mainBgColor">#C8E6C9</item> <item name="mainColor">#4CAF50</item> </style> <style name="AppTheme.Base.Blue"> <item name="colorPrimary">#2196F3</item> <item name="colorPrimaryDark">#1976D2</item> <item name="colorAccent">#607D8B</item> <item name="mainBgColor">#BBDEFB</item> <item name="mainColor">#2196F3</item> </style> <style name="AppTheme.Base.Purple"> <item name="colorPrimary">#673AB7</item> <item name="colorPrimaryDark">#512DA8</item> <item name="colorAccent">#795548</item> <item name="mainBgColor">#D1C4E9</item> <item name="mainColor">#673AB7</item> </style> <style name="AppTheme.Base.Grey"> <item name="colorPrimary">#607D8B</item> <item name="colorPrimaryDark">#455A64</item> <item name="colorAccent">#FFC107</item> <item name="mainBgColor">#CFD8DC</item> <item name="mainColor">#607D8B</item> </style>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
【three】第三步,设置控件的背景、字体颜色,字符串或图片:
<?xml version="1.0" encoding="utf-8"?> <Linerlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/mainColor" android:minHeight="?attr/actionBarSize" />1
2
3
4
5
6
7
8
9
10
11
这里只列出了颜色的例子android:background=”?attr/mainColor” ;
还可以使用“?attr/colorValue”、“?attr/stringValue”、“?attr/referenceValue”来引用主题中的颜色值、字符串以及图片。
【four】第四步,工具类中创建设置主题的方法:(关键一步)
private void setBaseTheme() { SharedPreferences sharedPreferences = getSharedPreferences( Consts.SHARE_NAME, MODE_PRIVATE); int themeType = sharedPreferences.getInt("theme_type", 0); int themeId; switch (themeType) { case THEME_GREEN: themeId = R.style.AppTheme_Base_Green; break; case ThEME_BLUE: themeId = R.style.AppTheme_Base_Blue; break; case THEME_ORANGE: themeId = R.style.AppTheme_Base_Orange; break; case THEME_TEAL: themeId = R.style.AppTheme_Base_Teal; break; case THEME_BROWN: themeId = R.style.AppTheme_Base_Brown; break; case THEME_GREY: themeId = R.style.AppTheme_Base_Grey; break; case THEME_PURPLE: themeId = R.style.AppTheme_Base_Purple; break; default: themeId = R.style.AppTheme_Base_Default; } setTheme(themeId); }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
要在Activity的onCreate方法里的setContextView前使用了。这里最好写在BaseActivity中,更具share保存的样式值,来动态设置theme。
【five】第五步,使界面主题生效:
谈到生效方法,当然直接设置后立即生效体验会好点,,但是系统限制,,正常的化需要重启Activity,也就是会出现闪屏问题。《方法1 》:自定义需要样式变换的所有View,
为了不重启activity, 自定义了所有需要样式变动的View, 原理为通过对rootView进行遍历,对所有实现了ColorUiInterface的view/viewgroup进行setTheme操作来实现即使刷新的。方式臃肿粗暴, 虽然是不需要重启activity,还可以针对每个view变换过程做动画,但是个人不推荐.
《方法2》:动态获取需要变更的控件,获取atts值,对每一个控件进行操作,也不需要重启Activity,但是有点繁琐。
ListView mNewsListView = (ListView) findViewById(R.id.listview); // 为ListView设置要修改的属性,在这里没有对ListView本身的属性做修改 ViewGroupSetter listViewSetter = new ViewGroupSetter(mNewsListView, 0); // 绑定ListView的Item View中的news_title视图,在换肤时修改它的text_color属性 listViewSetter.childViewTextColor(R.id.news_title, R.attr.text_color); // 构建Colorful对象 Colorful mColorful = new Colorful.Builder(this) .backgroundDrawable(R.id.root_view, R.attr.root_view_bg) // 设置view的背景图片 .backgroundColor(R.id.change_btn, R.attr.btn_bg) // 设置按钮的背景色 .textColor(R.id.textview, R.attr.text_color) // 设置文本颜色 .setter(listViewSetter) // 手动设置setter .create();1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
《方法3》乖乖的遵循重启Activity。为了美化转变效果,可以正对activity做一些动画,效果也是不错,看效果图:
【six】第六步,最后是在代码中设置控件的属性值的方法:
《方法1》TypedArray a = obtainStyledAttributes(new int[]{R.attr.mainBgColor, R.attr.mainColor}); int color = a.getColor(0, Color.BLACK)1
2
3
《方法2》
TypedValue typedValue = new TypedValue(); newTheme.resolveAttribute(mAttrResId, typedValue, true)1
2
3
聊聊其他方式的主题实现
APK主题方案和主题包保存到SD卡上(墨迹,搜狗实现方式)的方案类似,只不过是apk压缩格式,一些资源的引用可以调用系统api。APK主题方案的基本思路是:在Android中,所有的资源都是基于包的。资源以id进行标识,在同一个应用中,每个资源都有唯一标识。但在不同的应用中,可以有相同的id。因此,只要获取到了其他应用的Context对象,就可以通过它的getRsources获取到其绑定的资源对象。然后,就可以使用Resources的getXXX方法获取字符串、颜色、dimension、图片等。
要想获取其他应用的Context对象,Android已经为我们提供好了接口。那就是android.content.ContextWrapper.createPackageContext(String packageName, int flags)方法。
try { String remotePackage = "com.your.themepackagename"; Context remoteContext = createPackageContext(remotePackage, CONTEXT_IGNORE_SECURITY); Resources remoteResources = remoteContext.getResources(); text.setText(remoteResources.getText(remoteResources.getIdentifier("application_name", "string", remotePackage))); color.setTextColor(remoteResources.getColor(remoteResources.getIdentifier("color_name", "color", remotePackage))); image.setImageDrawable(remoteResources.getDrawable(remoteResources.getIdentifier("ic_icon", "drawable", remotePackage))); } catch (NameNotFoundException e) { e.printStackTrace(); }1
2
3
4
5
6
7
8
9
10
11
除了压缩包,apk包等实现方式,还可以考虑插件实现方式,目的都是更好的解耦,更方便的迭代项目.
相关文章推荐
- Android中的主题(theme)和样式(style)
- android的样式(style)与主题(theme)
- android style(样式)和theme(主题)设置
- Android 样式和主题(style & theme)
- android的样式(style)与主题(theme)
- android样式和主题(style&theme)
- 基于android样式与主题(style&theme)的详解
- android 中的样式(Style)和主题(Theme)资源
- Android下Notification,样式style,主题theme的功能实现
- Android样式(style)和主题(theme)资源介绍-android学习之旅(五十六)
- 安卓(android)的样式(style)和主题(theme)
- Android样式(style)和主题(theme)资源介绍-android学习之旅(五十六)
- android的样式(style)与主题(theme)
- android的样式(style)与主题(theme)
- Android学习之样式Style与主题theme
- 【android开发】修改主题theme(系统自带样式总结)
- Android style(样式)和theme(主题)设置
- android的样式(style)与主题(theme)
- Android样式(style)和主题(theme)资源介绍-android学习之旅(五十六)
- Android系统自带主题样式(android:theme),Android Dialog 系统样式