针对Android应用的换肤需求,通过Android-skin-support框架可以很好地优化APP的代码结构,不需要将所有皮肤的图片资源和xml放在一起,通过相关接口,加载相应主题的皮肤包即可完成换肤。
框架地址:https://github.com/ximsfei/Android-skin-support
框架的详细介绍和使用流程都可以参考github中的文档,这里主要介绍应用的换肤的实际操作流程。
Android-skin-support框架支持多种换肤方式,如自定义View换肤、应用内换肤、插件式换肤等,在本应用的换肤Demo中使用插件式换肤的方式。
通过新建Android application工程,创建主题皮肤包module
皮肤工程包名不能和宿主应用包名相同.
需要的换肤资源放到res目录下(同名资源)
如:默认主题下背景图片目录为
则新主题的皮肤包目录应为
且替换的图片或xml的命名要相同。
皮肤包的build.gradle配置要与宿主APP的配置相同。
因为每个皮肤包都是module,无法正常运行,所以就要用到Gradlew命令了,在Terminal中输入命令gradlew :module的名称:assembleDebug,这个命令是打Debug包的,当然也可以通过gradlew :module的名称:assembleRelease命令打 Release包。
导入依赖包
implementation 'skin.support:skin-support:2.2.3' // skin-support 基础控件支持 implementation 'skin.support:skin-support-design:2.2.3' // skin-support-design material design 控件支持[可选]
1.在Application的 onCreate中初始化
@Override public void onCreate() { super.onCreate(); sBtSettingApp = this; initSkinSupport(this); AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); } private void initSkinSupport(Application application) { Log.d(TAG, "initSkinSupport: 开始加载"); SkinCompatManager.withoutActivity(application) // material design .addInflater(new SkinMaterialViewInflater()) // windowBackground换肤 .setSkinWindowBackgroundEnable(true) // 关闭状态栏换肤 .setSkinStatusBarColorEnable(false) .loadSkin();
2.加入皮肤包
将换肤包放在src/main/assets/skins的文件夹下面,将皮肤包的名称的后缀由.apk改成.skin
3.添加权限
在AndroidManifest.xml文件中添加读写权限
4.根据主题加载相关皮肤包
switch (Theme) { case THEME_ECO: setTheme(R.style.Mystyle); SkinCompatManager.getInstance().loadSkin("eco.skin", SkinCompatManager.SKIN_LOADER_STRATEGY_ASSETS); break; case THEME_SPORT: setTheme(R.style.Mystyle); SkinCompatManager.getInstance().loadSkin("sport.skin", SkinCompatManager.SKIN_LOADER_STRATEGY_ASSETS); break;
2.2.4.1 AlertDialog
除了Activity之外的一些自定义控件的换肤,这里以自定义AlertDialog为例
1.首先实现SkincompatSupportable接口
2.在applySkin方法中实现换肤
@Override public void applySkin() { initSkin(); }
通过SkinCompatResources.getInstance()方法获取当前皮肤包图片资源
private void initSkin() { mDialogView.setBackground(SkinCompatResources.getInstance().getDrawable(R.drawable.name_edit_bg)); mButtonViewLine.setBackground(SkinCompatResources.getInstance().getDrawable(R.drawable.dialog_line_below)); mButtonDiver.setBackground(SkinCompatResources.getInstance().getDrawable(R.drawable.button_diver)); mDialogLine.setBackground(SkinCompatResources.getInstance().getDrawable(R.drawable.dialog_line)); mClose.setBackground(SkinCompatResources.getInstance().getDrawable(R.drawable.dialog_close_img)); mTitle.setTextColor(SkinCompatResources.getInstance().getColor(R.color.theme_title_color)); mInfo.setTextColor(SkinCompatResources.getInstance().getColor(R.color.theme_title_color)); }
然后在换肤时调用applySkin方法。
2.2.4.2 ListView
首先让View实现SkinCompatSupportable,ListView需要换肤的部分是按压后item的效果(selector)和滑动条(ScrollDrawable)
在applySkin中换肤,Selector属性可直接通过setSelector()设定
@Override public void applySkin() { setSelector(SkinCompatResources.getInstance().getDrawable(R.drawable.list_item_select)); setScrollDrawable(this, SkinCompatResources.getInstance().getDrawable(R.drawable.list_scroll_bar)); }
而滑动条属性只能在xml设置,java中并没有开放设置该属性的方法,因此只能通过反射得到,这里使用反射封装了一个方法setScrollDrawable()进行设置图片
private void setScrollDrawable(AlphaListView alphaListView,Drawable drawable){ try { Field mScrollCacheField = View.class.getDeclaredField("mScrollCache"); mScrollCacheField.setAccessible(true); Object mScrollCache = mScrollCacheField.get(alphaListView); // 从listview中获取bar Field scrollBarField = mScrollCache.getClass().getDeclaredField("scrollBar"); scrollBarField.setAccessible(true); Object scrollBar = scrollBarField.get(mScrollCache); Method setThumbDrawable = scrollBar.getClass(). getDeclaredMethod("setVerticalThumbDrawable", Drawable.class);//滚动条 setThumbDrawable.setAccessible(true); // Set your drawable here. setThumbDrawable.invoke(scrollBar, drawable); } catch (Exception e) { e.printStackTrace(); } }
更多内容可以参考github的官方文档,谢谢。