关于LayoutInflate和View-infalte的参数意义以及区别总结

关于LayoutInflate和View.infalte的参数意义以及区别总结

首先感谢AndroidDevelopment邪教群中月亮和六便士的讲解。接下来让我们步入正题:

Android中填充布局的两种方式

Android中用来填充布局的主要的两个方法如下:

  1. LayoutInflater.from(getContext()).inflate(resource, root, attachToRoot);
  2. View.inflate(context, resource, root);

根据个人习惯不同,可能大家使用方法不同,之前我是习惯使用 View.inflate(getContext(),R.layout.layout_main,null);方法的,直到有一天我遇到一个问题:

我发现使用该方法,为listView(RecycleView)填充item条目的时候,根布局设置的layout参数总是不起作用,后来了解,在这种情况下,其实根布局的所有的属性都是不管用的。

今天下午在邪教群 月亮和六便士 讲解里我了解了其中的原因:

View.inflate方法的原理

首先看下View.inflate方法的几个参数的意义:

第一个参数 Context。第二个参数,布局id,第三个参数root。这里主要讲下第三个参数,因为第三个参数我们一般都会传一个null,但是大都数人都不知道其中的原因。

首先来看下官方给出的方法注解:

/**
 * Inflate a view from an XML resource.  This convenience method wraps the {@link
 * LayoutInflater} class, which provides a full range of options for view inflation.
 *
 * @param context The Context object for your activity or application.
 * @param resource The resource ID to inflate
 * @param root A view group that will be the parent.  Used to properly inflate the
 * layout_* parameters.
 * @see LayoutInflater
 */
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
    LayoutInflater factory = LayoutInflater.from(context);
    return factory.inflate(resource, root);
}

注意看:A view group that will be the parent. Used to properly inflate the layout_* parameters.

前半句的意思是,该参数将作为一个你布局的父View,后半句意思是,使用你inflate布局的跟布局的layout_*参数,也就是你根布局layout_*参数将会生效。反之layout_*参数将会不生效。这样我们就可以理解为什么我们设置的跟布局参数无法生效了,因为我们该参数传了个null。

大家可能会说那我就讲parent传进去就好了呀,事情当然不会这么简单,比如我们在listView的getView方法中,将getView的参数作为inflate的第三个参数传入,就会报错,错误的意思是getView的返回的view已经有个parent不能再为其指定一个parent了,相信大家都知道getView方法中的parent是listView本身,不知道的去打印下。

这是为什么? 接着往下看你就会明白了:

/**
 * 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.,
 *        R.layout.main_page)
 * @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(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}

继续点击查看源码实际上,factory.inflate(resource, root);调用了inflate(resource, root, root != null)方法,

这个方法也就是LayoutInflater.from(getContext()).inflate(resource, root, attachToRoot);

LayoutInflater的inflate方法的三个参数

好,那么我们有必要解释下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.,
 *        R.layout.main_page)
 * @param root Optional view to be the parent of the generated hierarchy (if
 *        attachToRoot is true), or else simply an object that
 *        provides a set of LayoutParams values for root of the returned
 *        hierarchy (if attachToRoot 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(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {


第一个参数不多说 填入你定义好的布局

第二参数root也就是View.inflate(context, resource, root);的第三个参数,看下注解的解释:

root:

 * @param root Optional view to be the parent of the generated hierarchy (if
 *        attachToRoot is true), or else simply an object that
 *        provides a set of LayoutParams values for root of the returned
 *        hierarchy (if attachToRoot is false.)

​ 注解的大概意思就是:如果 attachToRoot 参数为true的时候,你inflate返回的view将会是parent本身,而parent将会调用addView方法添加到这个布局view中;如果attachToRoot参数为false的时候,inflate将把你的布局的参数,作为下次调用addView的方法的时候的布局依据。当然,上边说的这些都是在root不为空的前提下的。

attachToRoot:

 * @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.

这里多次用了attachToRoot参数,该参数的作用是什么,通过注解可以看到 该参数决定了infalte返回的view是root,还是你的布局view。

如果为true返回root,如果为false,返回的是你的View,那么我们有点蒙了,我们什么时候返回false,什么时候返回true。群里的@深圳-奕超同学说了一个可能就是如果你的resource的跟布局是一个标签的话就必须使用true了,原因是:

inflate的时候如果不指定root并指定为true,那么infate返回的是被填充资源的根布局。
而如果为merge标签,merge本身不是一个view,Android在填充这个布局讲merge转成view的时候会报错,因为merge没有对应的Java对象。

好现在我们应该能得到的结论是:inflate(resource, root, attachToRoot); root参数是否制定,会影响你的view根布局参数是否会生效。

attachToRoot参数的true 和 false 将决定你的infalte方法返回值是root还是你的填充资源的根布局。

view.infalte root参数报错的问题

那么回到之前的问题,view.infalte中的第三个参数传入parent就会报错的问题

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}

上边,这段代码是view.infalte将会走的方法,可以看见如果我们指定root对象,他就会将attachToRoot设置为true,然后根据之前的讲解,如果attachToRoot为true,inflate返回的View就会是root本身(布局view已经作为子view添加到rootView)。而listVIew中的parent参数就是listView本身,那么在getView中又返回了listView,listView本身是父View的,这时候我们相当于把listView作为Item又添加到listView中,这时候我们先相当于又给其指定了一个父View即listView,这时候报错也是必然的了,因为一个view只能有一个父View。

继续深入了解inflate

下面继续深入理解下inflate(resource, root, attachToRoot);后两个参数的作用:

假设这样一个场景:

我用一ViewGroup1(相对布局),里边有个btn。我现在想通过inflate的方法为这个ViewGroup添加一个子View,并放在btn的右边

<LinearLayout
    .....
    android:Layout_toRightOf:"@+id/btn"
    />

我们的inflate参数是这样写的:

View view = inflate(R.Layout.linear_layout,viewGroup2,false);注意:viewGroup2也是个相对布局,但是并不是viewGroup1

然后调用,viewGroup1.addView(view),这时候view会不会位于btn的右侧?

答案是肯定的,如果你足够明白上边所讲的知识,inflate(R.Layout_linear_layout,viewGroup2,false),方法将会是R.layout.linear_layout的根布局参数生效。当viewGroup1.addView(view)则按照view的跟布局参数设置view的位置

那好,我们将ViewGroup1换成线性布局会发生什么事呢,聪明的你肯定猜到了,view肯定不会再btn右侧了
(这个如果你的线性布局水平布局的话还是有可能的,当然我们讲的中点不是这个)

我们要说的是,造成这个结果原因是,虽然我们view的根布局有toRightof的属性,但是Linearlayout根本不认呀。

总结

好最后放大招总结:inflate(resource, root, attachToRoot);

  1. 如果root为null,attachToRoot失去作用,true or false 并没有作用
  2. 如果root不为null,attachToRoot设置为true,则把加载的布局指定一个父View,即root

此时,inflate返回的是添加了你的布局的root。

  1. 如果root不为null,attachToRoot设置为true,则布局文件的最外层的所有layout参数生效,再该view被添加到
    一个父view时候,将会使用这些layout参数的值
  2. 当不设置attachToRoot的时候,指定root参数,默认attachToRoot的值为true,
  3. 如果给填充的布局文件指定了layout睡醒,但是root中并没有对应的layout属性,则会忽略掉这些属性
  4. 如果给填充的布局文件指定了layout属性,root中也对应的属性,但真正要添加的父view中并没有
    这些属性的时候,该layout也不会生效,会被忽略。



关于LayoutInflate和View-infalte的参数意义以及区别总结_第1张图片关于LayoutInflate和View-infalte的参数意义以及区别总结_第2张图片

你可能感兴趣的:(Android进阶)