LayoutInflater的获取方式有两种:
LayoutInflater lif = LayoutInflater.from(Context context);
LayoutInflater lif = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
LayoutInflater.from(context)的源码可知,它就是对
context.getSystemService()的一种安全封装,所以更建议使用LayoutInflater.from(context)的方式。
LayoutInflater.inflate比较常用的2个重载方法:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
LayoutInflater.inflate(layoutId,rootView,attchToRoot)
layoutId 对应的布局文件;
rootView 对应的父容器;
attchToRoot 是否添加到rootView中。
inflate(resource,root)其实调用的也是infalte(resource,root,attachToRoot),第三个参数根据root是否为空自动赋值。
情形1:
mInflater.inflate(R.layout.view_textview, null),
mInflater.inflate(R.layout.view_textview, null, true),
mInflater.inflate(R.layout.view_textview, null, false),
这三种方式返回的都是对应布局中的tempView,不会设置layoutParams,也没有rootView可以添加;当前view的LayoutParams由添加它的ViewGroup决定。
情形2:
mInflater.inflate(R.layout.view_textview, parent),
mInflater.inflate(R.layout.view_textview, parent, true),
源码中有这样一段:
if (root != null && attachToRoot) {
root.addView(temp, params);
}
这两种都是创建temp的View,params获取的是root的LayoutParams,然后执行root.addView(temp, params);最后返回root。
当root不为null,attachToRoot为true时,表示将resource指定的布局添加到root中,添加的过程中resource所指定的的布局的根节点的各个属性都是有效的。
情形3:
mInflater.inflate(R.layout.view_textview, parent, false),
源码中有这样一段:
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);
}
}
创建temp的View,然后执行temp.setLayoutParams(params);然后再返回temp。
如果root不为null,而attachToRoot为false的话,表示不将第一个参数所指定的View添加到root中,那么这个时候有的小伙伴可能就有疑问了,既然不添加到root中,那我还写这么多干嘛?我第二个参数直接给null不就可以了?其实不然,这里涉及到另外一个问题:我们在开发的过程中给控件所指定的layout_width和layout_height到底是什么意思?该属性的表示一个控件在容器中的大小,就是说这个控件必须在容器中,这个属性才有意义,否则无意义。这就意味着如果我直接将linearlayout加载进来而不给它指定一个父布局,则inflate布局的根节点的layout_width和layout_height属性将会失效(因为这个时候linearlayout将不处于任何容器中,那么它的根节点的宽高自然会失效)。如果我想让linearlayout的根节点有效,又不想让其处于某一个容器中,那我就可以设置root不为null,而attachToRoot为false。这样,指定root的目的也就很明确了,即root会协助linearlayout的根节点生成布局参数,只有这一个作用。
if (root == null || !attachToRoot) {
result = temp;
}
这里返回的结果中,如果root!=null&&attachToRoot,返回的就是root;否则都是返回temp的view。
注意:
1.如果resource根布局是以<merge>标签开始,则root不能为空,且必须attachToRoot。
2.如果是在
AdapterView中,attachToRoot必须为false,否则报出:
java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView
3.如果root!=null&&attachToRoot不为空,需要注意不再要将当前的已被其他parentViewadd的View添加到其他的View上,否则报出:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.