本文为过往笔记整理, 在此只作记录,不做严谨的技术分享。
root参数
- root != null:
- attachToRoot = true,View根布局宽高有效,添加到root中,返回root;
- attachToRoot = fase,View根布局宽高有效,不添加到root中,返回View;
- root == null:attachToRoot = true/false,View根布局宽高无效,不添加到root中,返回View;
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
final AttributeSet attrs = Xml.asAttributeSet(parser);
//注意返回的是root还是View
View result = root;
try {
if (TAG_MERGE.equals(name)) {
} else {
//Temp is the root view that was found in the xml
//临时View,xml的各个属性,不包括宽高,还未填充子View
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
//根据根布局中宽高属性,生成相应父View的LayoutParams
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
//不需要添加到root,将宽高设置到temp
temp.setLayoutParams(params);
}
}
//递归加载xml中的子View,并添加到temp。
//最后,在此处调用onFinishInflate()方法通知加载完成。
rInflateChildren(parser, temp, attrs, true);
// 此时返回的是root
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// 返回View
if (root == null || !attachToRoot) {
result = temp;
}
}
}
return result;
}
}
onFinishInflate调用
当xml中的View标签被映射成View对象时,会调用该View的onFinishInflate方法
- 该方法只有在布局文件中加载View时会回调,如果直接new View实例则不会被回调
- 在Activity初始化过程中:加载xml是在setContent中被调用的,也就是由ActivityThread.performLaunchActivity触发的
- 所以onFinishInflate方法的触发时机在onCreate --> onFinishInflate --> onResume中
- 此时还没有进行View的测量、布局、绘制,所以无法得到宽高、坐标等信息
final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
boolean finishInflate) throws XmlPullParserException, IOException {
rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
}
void rInflate(XmlPullParser parser, View parent, Context context,
AttributeSet attrs, boolean finishInflate){
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
final String name = parser.getName();
if (TAG_REQUEST_FOCUS.equals(name)) {
} else if (TAG_TAG.equals(name)) {
} else if (TAG_INCLUDE.equals(name)) {
} else if (TAG_MERGE.equals(name)) {
} else {
//生成子View实例对象。
final View view = createViewFromTag(parent, name, context, attrs);
//子View宽高LayoutParams
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
//1: 递归解析子View下层的View,注意第四个参数是true,也就是下文的finishInflate=true
rInflateChildren(parser, view, attrs, true);
//添加
viewGroup.addView(view, params);
}
}
if (finishInflate) {
//2: 通知View加载完成
parent.onFinishInflate();
}
}
- 注释1:递归+while循环中,不断遍历子View直到最深的View
- 注释2:递归中,无论有没有子View都会被调用;从里往外层触发onFinishInflate