问题:
我有一个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,attachToRoot); } finally { parser.close(); } }
大家已经注意到了,两个参数的inflate方法其实也是调用三个参数的inflate方法,
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,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,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,false) 返回的view是 xml的根view 但是此时他拥有xml中设置的 layout_width和 layout_height
到这,这个问题已经理清了。