当我们在自定义布局或者在RecyclerView的onBindViewHolder方法中使用下面的方法进行布局加载
View view = View.inflate(parent.getContext(), R.layout.item_layout, null);
但是上面的方法中ViewGroup的参数到底是传值呢,还是不传呢?
并且和View view= LayoutInflater.from(context).inflate(R.layout.item_layout, parent, false);
这个又有啥区别呢?
现在我们进行源码分析
- 进入View的inflate方法
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}
发现原来最终是使用LayoutInflater.from(context).inflate(resource, root);
来调用的inflate方法
2.继续进入是LayoutInflater类的inflate方法,如下:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
这里又是调用的是inflate(resource,root,root!= null);
虽然前面没有attachToRoot这个参数,但是在这里有调用了带attachToRoot这个参数的方法,并且根据root的是否为null传入该参数。
3.继续进入inflate方法
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
到这里才是才是所有的方法的入口,这个方法中主要是把传入的布局进行解析
4.进入inflate(parser,root,attachToRoot);
方法,这个方法中主要做了
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
....
View result = root;
....
if (TAG_MERGE.equals(name)) {
....
} else {
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true);
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}
.....
return result;
}
}
进行分析,View result = root,且ViewGroup的LayoutParams首先会被设置为null,
①当root为null或者attachToRoot为false时,ViewGroup的LayoutParams会为null,并将temp赋值给result进行返回。
②当root不为null时,params才会被赋值,同时attachToRoot为false时才会把params设置给temp,temp是啥?就是根据inflate传递的参数生成的view。
③当root不为null时,同时attachToRoot为true时,会调用root.addView(temp, params);
这里也就是当我们在RecyclerView的onCreateViewHolder方法中使用View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, true);
时会报下面这个错:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
网友评论