LayoutInflater.inflate()的功能:将一段 XML 资源文件加载成为 View
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();
}
}
在源码中通过通过XmlResourceParser去解析xml获取xml信息,保存在parser这个对象里面,然后调用inflate(parser, root, attachToRoot)去添加这个资源文件下的view,构建一个view。
其中,对于inflate()函数传递不同参数分别有不同的效果:
view的onMeasure方法:主要做的就是根据ViewGroup传入的测量模式和测量值,计算自己应该的宽和高:
一般是这样的流程:
如果宽的模式是AT_MOST:则自己计算宽的值。一般是wrap_content
如果宽的模式是EXACTLY:则直接使用MeasureSpec.getSize(widthMeasureSpec);设置固定值或者match_parent
接下来我们通过源码分析:
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
通过上述代码,产生view控件。
View result = root;
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// 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;
}
}
由上述代码可知,当root不为null:
attachToRoot = false时,root生成的LayoutParams给当前temp,因此它的宽高是正常的
attachToRoot = true时,root生成的LayoutParams给当前temp,并且将view添加到root里面,因此它会在view里面显示出来
当root == null 或者 attachToRoot = false时,返回当前view,attachToRoot = true时返回的是root,所以当前显示的布局是root的话,这样才可以将view显示出来,否则view显示不出来。
举例分析:
public class TestActivity extends AppCompatActivity {
private static final String TAG = "TestActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_test);
LayoutInflater layoutInflater = LayoutInflater.from(this);
View view1 = layoutInflater.inflate(R.layout.activity_test,null);
Log.d(TAG,"Test view1 = " + view1+"view1: "+view1.getLayoutParams()+" ");
View view2 = layoutInflater.inflate(R.layout.activity_test, (ViewGroup) findViewById(android.R.id.content),false);
Log.d(TAG,"Test view2 = " + view2+" view2: "+view2.getLayoutParams()+" ");
View view3 = layoutInflater.inflate(R.layout.activity_test, (ViewGroup) findViewById(android.R.id.content),true);
Log.d(TAG,"Test view3 = " + view3+"view3: "+view3.getLayoutParams()+" ");
}
}
布局文件:
运行效果:分别是view1,view2,view3
打印的信息:
D/TestActivity: Test view1 = android.support.v7.widget.AppCompatButton{6eb543a VFED..C.. ......I. 0,0-0,0 #7f070022 app:id/bt}view1: null
D/TestActivity: Test view2 = android.support.v7.widget.AppCompatButton{2c49cbc VFED..C.. ......I. 0,0-0,0 #7f070022 app:id/bt} view2: android.widget.FrameLayout$LayoutParams@ae03445
D/TestActivity: Test view3 = android.support.v7.widget.ContentFrameLayout{893c643 V.E...... ......I. 0,0-0,0 #1020002 android:id/content}view3: android.support.v7.widget.ActionBarOverlayLayout$LayoutParams@82604c0
@Override
public void addView(View child) {
throw new UnsupportedOperationException("addView(View) is not supported in AdapterView");
}