问题:
我有一个FrameLayout(后面简称frame),我有一个需求,是动态向这个frame中添加一个使用xml定义子view(后面简称xmlview),一般的方法都是使用LayoutInflater动态inflate一个view,然后调用
frame.addViiew,结果发现xmlview的根布局的layout_width 和 layout_height 一直不生效,这特么是什么鬼,不管怎么改都不行,撞鬼了么
原因剖析:
主要原因还是我们对LayoutInflater类中的inflate函数认知不清导致的。
首先,先贴上相关源码:
/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
*
* @param resource ID for an XML layout resource to load (e.g.,
* <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy.
* @return The root View of the inflated hierarchy. If root was supplied,
* this is the root View; otherwise it is the root of the inflated
* XML file.
*/
public View inflate(int resource, ViewGroup root) {
return inflate(resource, root, root != null);
}
/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
*
* @param resource ID for an XML layout resource to load (e.g.,
* <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy (if
* <em>attachToRoot</em> is true), or else simply an object that
* provides a set of LayoutParams values for root of the returned
* hierarchy (if <em>attachToRoot</em> is false.)
* @param attachToRoot Whether the inflated hierarchy should be attached to
* the root parameter? If false, root is only used to create the
* correct subclass of LayoutParams for the root view in the XML.
* @return The root View of the inflated hierarchy. If root was supplied and
* attachToRoot is true, this is root; otherwise it is the root of
* the inflated XML file.
*/
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
if (DEBUG) System.out.println("INFLATING from resource: " + resource);
XmlResourceParser parser = getContext().getResources().getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
大家已经注意到了,两个参数的inflate方法其实也是调用三个参数的inflate方法,
如果调用(下面伪代码中 frameParent 不为空 )
inflate(R.layout.demo, frameParent) 则相当于是调用了inflate(R.layout.demo, frameParent, true)
让我们接下来深入infalte具体的执行代码(篇幅问题,只截取了最重要的部分)
// Temp is the root view that was found in the xml
View temp;<span style="color:#ff0000;">//这个temp就是xml的根view</span>
if (TAG_1995.equals(name)) {
temp = new BlinkLayout(mContext, attrs);
} else {
temp = createViewFromTag(root, name, attrs);
}
ViewGroup.LayoutParams params = null;
if (root != null) { //这个root就是使用inflate时候的第二个参数 如果root为null,xml根view<span style="font-family: Arial, Helvetica, sans-serif;">则</span><span style="font-family: Arial, Helvetica, sans-serif;">会丢失width height 属性</span>
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);<span style="color:#ff0000;">//这个大家可以自行研究下 就是根据xml中声明的属性来创建的</span>
if (!attachToRoot) { //只要你传了root进来,不管是否attch xml的根都会有自己原先在xml设置的属性
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
if (DEBUG) {
System.out.println("-----> start inflating children");
}
// Inflate all children under temp
rInflate(parser, temp, attrs, true);
if (DEBUG) {
System.out.println("-----> done inflating children");
}
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {<span style="font-family: Arial, Helvetica, sans-serif;">//如果使用了attachToRoot 那么xml的布局将会直接添加到root中 </span>
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;
}
相信通过上面的代码大家已经知道为什么xml中根view会丢失width以及heigh属性了吧,原因就是:你在调用inflate函数时候,传了一个null的父布局。
inflate(R.layout.demo, null)
接下来还有一个小点要讲述一下:
inflate(R.layout.demo, null) 返回的view 是 xml本身的根view 丢失了设置的layout_width 以及 layout_height
inflate(R.layout.demo, parent)以及 inflate(R.layout.demo, parent, true) 返回的view 是 parent ,而不是xml的根布局</span>
inflate(R.layout.demo, parent, false) 返回的view是 xml的根view 但是此时他拥有xml中设置的 layout_width和 layout_height