LayoutInflater原理学习笔记

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的大小可以生效。
参考网址:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值