在开发迭代中,有这么一个场景:
我们给
TextView
定制了不少功能,在下一个版本,需要把程序中的所有TextView
都替换成我自己的CustomTextView
,这个时候你会怎么做?有没有一种方法在不改动布局文件的情况下就能实现动态替换呢?
原理:layout.xml -> Java 对象
首先我们知道一个 layout.xml
转成 Java
对象,使用的是 LayoutInflater#inflate
方法。
其内部是通过 xml 解析器,解析到标签比如: Linearlayout
,
inflate()
会调用createViewFromTag()
实例化Linearlayout
对象;createViewFromTag()
方法内部使用了一个Factory
对象;Factory
会调用Factory#onCreateView()
来实例化这个Linearlayout
。
伪代码如下:
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
|
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
...
final String name = parser.getName();
...
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
}
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;
}
...
view = createView(name,
null, attrs);
}
|
所以我只要给 LayoutInflater
设置一个我们自定义的 Factory
就可以实现动态替换View。
1
2
3
4
5
|
public void setFactory(Factory factory) {
}
public void setFactory2(Factory2 factory) {
}
|
替换方法
其实在 Activity 本身就是一个 LayoutInflater$Factory
1
2
3
4
5
6
7
|
public
class Activity extends ContextThemeWrapper
implements
LayoutInflater.
Factory2,
Window.
Callback,
KeyEvent.
Callback,
OnCreateContextMenuListener,
ComponentCallbacks2,
Window.
OnWindowDismissedCallback,
WindowControllerCallback {
}
|
所以我们只需要实现 Activity 的 onCreateView 就可以实现 View 的动态替换。
1
2
3
4
5
6
7
8
9
|
public
class MyActivity extends Activity {
public View onCreateView(String name, Context context, AttributeSet attrs) {
if (name.equals(
"TextView")) {
return
new CustomTextView(context, attrs);
}
return suqer.onCreateView(name, context, attrs);
}
}
|
插播广告:OTCBTC 是目前最流畅、最靠谱、最好用的场外交易平台,支持支付宝、微信、银行卡支付购买BTC、ETH、EOS、USDT、QTUM、ZEC、GXS、BCH 等数字币。现在注册,即可领取比特币红包! https://otcbtc.com/referrals/904529093