在开发迭代中,有这么一个场景:
我们给 TextView
定制了不少功能,在下一个版本,需要把程序中的所有 TextView
都替换成我自己的 CustomTextView
,这个时候你会怎么做?有没有一种方法在不改动布局文件的情况下就能实现动态替换呢?
原理:layout.xml -> Java 对象
首先我们知道一个 layout.xml
转成 Java
对象,使用的是 LayoutInflater#inflate
方法。
其内部是通过 xml 解析器,解析到标签比如: Linearlayout
,
-
inflate()
会调用createViewFromTag()
实例化Linearlayout
对象; -
createViewFromTag()
方法内部使用了一个Factory
对象; -
Factory
会调用Factory#onCreateView()
来实例化这个Linearlayout
。
伪代码如下:
publicViewinflate(XmlPullParser parser, ViewGroup root,booleanattachToRoot){ ... finalString name = parser.getName(); ... finalView temp = createViewFromTag(root, name, inflaterContext, attrs); } View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,booleanignoreThemeAttr){ ... View view; if(mFactory2 !=null) { view = mFactory2.onCreateView(parent, name, context, attrs); } elseif(mFactory !=null) { view = mFactory.onCreateView(name, context, attrs); } else{ view = null; } ... view = createView(name, null, attrs); }
所以我只要给 LayoutInflater
设置一个我们自定义的 Factory
就可以实现动态替换View。
publicvoidsetFactory(Factory factory){ } publicvoidsetFactory2(Factory2 factory){ }
替换方法
其实在 Activity 本身就是一个 LayoutInflater$Factory
publicclassActivityextendsContextThemeWrapper implementsLayoutInflater.Factory2, Window.Callback,KeyEvent.Callback, OnCreateContextMenuListener,ComponentCallbacks2, Window.OnWindowDismissedCallback,WindowControllerCallback{ }
所以我们只需要实现 Activity 的 onCreateView 就可以实现 View 的动态替换。
publicclassMyActivityextendsActivity{ publicViewonCreateView(String name, Context context, AttributeSet attrs){ if(name.equals("TextView")) { returnnewCustomTextView(context, attrs); } returnsuqer.onCreateView(name, context, attrs); } }