LayoutInflater原理学习笔记

来源:互联网 发布:cba球员卧推数据 编辑:程序博客网 时间:2024/06/05 16:36
1、获取LayoutInflater实例方法

(1)LayoutInflater inflater=LayoutInflater.from(context);
   注:方法一只是对方法二的一个封装
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;    }
(2)
LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
2、引入布局方法
(1)
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {        return inflate(resource, root, root != null);    }
</pre><pre>
(2)
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
  注:该方法最终调用方法(4),源码片段如下
final XmlResourceParser parser = res.getLayout(resource);        try {            return inflate(parser, root, attachToRoot);        } finally {            parser.close();        }
(3)
public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {        return inflate(parser, root, root != null);    }
</pre><pre>
(4)
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)

3、源码解析

(1)首先将传入的XmlPullParser进行解析

(2)如果节点名和TAG_MERGE相同,则不创建新的View对象
if (TAG_MERGE.equals(name)) {                    if (root == null || !attachToRoot) {                        throw new InflateException("<merge /> can be used only with a valid "                                + "ViewGroup root and attachToRoot=true");                    }                    rInflate(parser, root, inflaterContext, attrs, false);                }

(3)如果节点名与TAG_MERGE不同则调用createViewFromTag()根据节点名创建一个新的View对象temp。之后首先判断若(root!=null),则将params的值设为root.generateLayoutParams(attrs)。之后判断attachToRoot是否为真,若为真则直接root.addView(temp,params),并且返回root;若为假则将params参数传入temp中,并且返回temp。若(root==null)则直接返回不带params参数的temp。
View result = root;
final View temp = createViewFromTag(root, name, inflaterContext, attrs);                    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);                        }                    }                    if (DEBUG) {                        System.out.println("-----> start inflating children");                    }                    // Inflate all children under temp against its context.                    rInflateChildren(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) {                        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;                    }                }            } catch (XmlPullParserException e) {                InflateException ex = new InflateException(e.getMessage());                ex.initCause(e);                throw ex;            } catch (Exception e) {                InflateException ex = new InflateException(                        parser.getPositionDescription()                                + ": " + e.getMessage());                ex.initCause(e);                throw ex;            } finally {                // Don't retain static reference on context.                mConstructorArgs[0] = lastContext;                mConstructorArgs[1] = null;            }            Trace.traceEnd(Trace.TRACE_TAG_VIEW);            return result;

 (4)rInflaterChidren()循环遍历该视图下的子视图。同样通过创建新的View对象,并且直接将这些子View对象加入该视图中。
final View view = createViewFromTag(parent, name, context, attrs);                final ViewGroup viewGroup = (ViewGroup) parent;                final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);                rInflateChildren(parser, view, attrs, true);                viewGroup.addView(view, params);

 在学习郭神关于LayoutInflater解析的博客的时候受益匪浅,不过却发现一个问题。郭神在博客中举了一个例子,就是用LayoutInflater引入一个按钮布局并且调用addView()将按钮置于mainlayout中。此时修改Button的layout_width和layout_height不起作用,郭神给的解释是Button不存在于任何布局当中,所以这两个属性不能起作用。之后郭神在Button的XML文件中加了一个RelativeLayout包住了Button,之后layout_width和layout_height起作用了。将整个流程看下来,发现原因应该不是这样的。下面是原博中的代码片段:
setContentView(R.layout.activity_main);          mainLayout = (LinearLayout) findViewById(R.id.main_layout);          LayoutInflater layoutInflater = LayoutInflater.from(this);          View buttonLayout = layoutInflater.inflate(R.layout.button_layout, null);          mainLayout.addView(buttonLayout); 
<Button xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="300dp"      android:layout_height="80dp"      android:text="Button" >    </Button>
上面为代码片段1,此时修改大小不能生效。
</pre><pre name="code" class="java" style="background-color: inherit;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="match_parent" >      <Button          android:layout_width="300dp"          android:layout_height="80dp"          android:text="Button" >      </Button>  </RelativeLayout>  

上面为代码片段2,此时修改大小生效。


我的理解:在片段1中,引入button_layout时root布局为null,因此如前文所说将直接返回一个不带params参数信息的temp视图,因此设置layout_width和layoutout_height并不会传入新建的视图中,而是在addView()时由于没有传入LayoutParams参数便由其内部的generateDefaultLayoutParams()方法生成一个默认尺寸。而在片段二中,加入一个RelativeLayout之后,首先会建立RelativeLayout的视图。然后在rInflaterChildren()中遍历RelativeLayout的子视图并创建它们,Button就是在这时创建的,而在rInflateChidren()方法中调用的是addView(view,params)将Button加入RelativeLayout所以带有XML文件中的尺寸信息,因此调整Button的大小可以生效。
参考网址:
郭神关于LayoutInflater原理解析博客地址:http://blog.csdn.net/guolin_blog/article/details/12921889
Android-Reference-LayoutInflater:http://developer.android.com/intl/zh-cn/reference/android/view/LayoutInflater.html





0 0
原创粉丝点击