android插件化主题方案 (上--LayoutInflateFactory的使用)
来源:互联网 发布:淘宝联盟默认推广位 编辑:程序博客网 时间:2024/05/17 07:36
android插件化主题方案 (上–LayoutInflateFactory的使用)
标签(空格分隔): android 主题 皮肤 插件化
“做成网易音乐那样的!”
这次产品经理提出的需求就是像网易音乐那样可以更换主题皮肤,当然皮肤切换很多app都有,产品经理也明确表示需要后台有皮肤主题管理能力,所以这次的功能免不了要做成外挂式,不能简单的在资源文件编写多套value的方式实现。
那我们就来一步步的实现吧。
首先,我们先不管插件化的方式,先来看看如何在不更改已编写xml的情况下,快速替换view的资源。
setContentView()做了些什么?
我们知道默认onCreate()执行时,马上会调用setContentView(int id)方法,将layout资源与activity进行绑定,我们看看setContentView做了些什么。
public void setContentView(@LayoutRes int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar();}
这是Activity类中的setContentView()的方法,我们继续往下看。
@Override public void setContentView(int layoutResID) { if (mContentParent == null) { installDecor(); } else { mContentParent.removeAllViews(); } mLayoutInflater.inflate(layoutResID, mContentParent); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); } }
在这里我们看到了熟悉的充气类,我们View的创建离不开Inflate,那么它在创建View的时候做了什么呢?
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { .... final View temp = createViewFromTag(root, name, inflaterContext, attrs); ...}
我们找到这个创建view的方法
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs, boolean ignoreThemeAttr) { ... View view; if (mFactory2 != null) { view = mFactory2.onCreateView(parent, name, context, attrs); } else if (mFactory != null) { view = mFactory.onCreateView(name, context, attrs); } else { view = null; } if (view == null && mPrivateFactory != null) { view = mPrivateFactory.onCreateView(parent, name, context, attrs); } ... }
最终我们的view是通过factory进行创建的,
而这个factory就是我们这次需要重点介绍的工具。
/** * Used with {@code LayoutInflaterCompat.setFactory()}. Offers the same API as * {@code LayoutInflater.Factory2}. */public interface LayoutInflaterFactory { /** * Hook you can supply that is called when inflating from a LayoutInflater. * You can use this to customize the tag names available in your XML * layout files. * * @param parent The parent that the created view will be placed * in; <em>note that this may be null</em>. * @param name Tag name to be inflated. * @param context The context the view is being created in. * @param attrs Inflation attributes as specified in XML file. * * @return View Newly created view. Return null for the default * behavior. */ public View onCreateView(View parent, String name, Context context, AttributeSet attrs);}
LayoutInflateFactory是一个接口,其只有一个方法,我们重点关注注释,简单理解为
提供给你一个钩子(可以理解为监听),用以在inflate的时候用名字作为比对,生成对应的View对象进行返回。
so,整个inflate的过程大致就是,xmlParser对xml进行解析,然后传递至Factory根据名字生产相对应的View类,然后返回上层进行添加,好了,下面,我们就可以通过实现这个接口,在onCreate()中对生成的view设置各种属性,这样,我们就能在xml中书写固定的资源情况下,动态对view的属性进行更改。
自定义Factory
@Overridepublic View onCreateView(View parent, String name, Context context, AttributeSet attrs) { boolean isSkinEnable = attrs.getAttributeBooleanValue(SkinConfig.NAMESPACE, SkinConfig.ATTR_SKIN_ENABLE, false); AppCompatDelegate delegate = mAppCompatActivity.getDelegate(); View view = delegate.createView(parent, name, context, attrs); if (view instanceof TextView && SkinConfig.isCanChangeFont()) { TextViewRepository.add(mAppCompatActivity, (TextView) view); } if (isSkinEnable || SkinConfig.isGlobalSkinApply()) { if (view == null) { view = ViewProducer.createViewFromTag(context, name, attrs); } if (view == null) { return null; } parseSkinAttr(context, attrs, view); } return view;}
这里的isSkinEnable我们用来在xml标记该view需要更换皮肤(自定义命名空间),下面判断TextView的部分用来处理更换字体,暂且不看,其余的创建View的方法于源码相同,创建View之后,我们用parseSkinAttr()方法进行view的处理,当然之前我们需要判断该view是否需要进行切换。
在这个方法中,我们就可以对这个view进行各种处理,更改背景,更改imageView的src等等。
waring
这个factory只用于在界面初始化(比如打开一个activity)的时候进行主题的更改,在界面被绘制完毕后,我们需要更改这个界面所有view的属性的话,得调用其他方法,所以为了标记那些view需要更改,我们在这个方法中可以定义一个集合,在初始化的时候进行保存,以方便后续处理。
SkinItem skinItem = new SkinItem(); skinItem.view = view; skinItem.attrs = viewAttrs; mSkinItemMap.put(skinItem.view, skinItem);
skinItem就是需要更改的view及其属性的封装对象。
替换activity的factory为自定义的factory
@Overrideprotected void onCreate(Bundle savedInstanceState) { mSkinInflaterFactory = new SkinInflaterFactory(); mSkinInflaterFactory.setAppCompatActivity(this); LayoutInflaterCompat.setFactory(getLayoutInflater(), mSkinInflaterFactory); super.onCreate(savedInstanceState); changeStatusColor();}
这里我建议书写一个baseActivity,在super.onCreate之前将activity与Factory进行绑定。
这样在每一个activity启动之后,创建view时,我们都可以控制到该view的属性,而我们将这些view保存之后,我们同样可以在activity已经创建完毕的条件下,准确找到需要更改的view并对其做相应的修改操作。
- android插件化主题方案 (上--LayoutInflateFactory的使用)
- android插件化主题方案(下-调用其他apk包的资源)
- Android主题切换方案
- 主题 : 使用VS插件在VS2012/2013上编辑和调试cocos2d-x的Lua代码
- Wordpress的主题与插件的使用
- Android插件化系列第(五)篇---Activity的插件化方案(代理模式)
- 基于android的主题插件编写
- Android Studio 主题插件
- Android主题切换方案总结
- Android主题切换方案总结
- Android主题切换方案总结
- Android 不同版本的主题切换方案/AndroidThemeChange
- Android 使用主题(Theme)
- Android 使用主题(Theme)
- Eclipse使用配色方案 Eclipse颜色主题插件:Eclipse Color Theme
- sencha touch 扩展篇之使用sass自定义主题样式 (上)使用官方的api修改主题样式
- sencha touch 扩展篇之使用sass自定义主题样式 (上)使用官方的api修改主题样式
- 滴滴的插件化方案
- Hbase原理、基本概念、基本架构
- js多选框常用方法
- 遇到适配7.0系统,遇到provider冲突问题
- 结合代码了解springMVC原理
- 不知道叫什么好
- android插件化主题方案 (上--LayoutInflateFactory的使用)
- php导出excel表格
- Eclipse--java反编译插件
- 51nod1058 N的阶乘的长度+51nod1130 N的阶乘的长度 V2(斯特林近似) 学习斯特林公式
- HEVC函数入门(18)——帧间预测的原理
- Android系统框架
- X264使用指南
- 关于Android 使用MediaRecorder实现录制视频开始暂停和结束功能的说明
- android蓝牙开发