LayoutInflater attachToRoot参数是什么意思?

Jef*_*rod 169 android android-layout layout-inflater android-view

LayoutInflater.inflate文档是不看好的目的十分清楚我的attachToRoot参数.

attachToRoot:膨胀的层次结构是否应附加到根参数?如果为false,则root仅用于为XML中的根视图创建LayoutParams的正确子类.

有人可以更详细地解释,特别是根视图是什么,并且可能显示一个行为truefalse值之间的变化的例子?

Roh*_*ngh 106

现在或不现在

"第三个"参数attachToRoot的真或假之间的主要区别是这个.

当你把attachToRoot

true:将子视图添加到父级RIGHT NOW
false:将子视图添加到父级NOT NOW.
稍后再添加.`

如果是

以后是你用于例如 parent.addView(childView)

一个常见的误解是,如果attachToRoot参数为false,则子视图将不会添加到父视图.错误
在这两种情况下,子视图都将添加到parentView.这只是时间问题.

inflater.inflate(child,parent,false);
parent.addView(child);   
Run Code Online (Sandbox Code Playgroud)

相当于

inflater.inflate(child,parent,true);
Run Code Online (Sandbox Code Playgroud)

BIG NO-NO
如果您不负责将子视图添加到父级,则不应将attachToRoot传递为true.
例如,添加片段时

public View onCreateView(LayoutInflater inflater,ViewGroup parent,Bundle bundle)
  {
        super.onCreateView(inflater,parent,bundle);
        View view = inflater.inflate(R.layout.image_fragment,parent,false);
        .....
        return view;
  }
Run Code Online (Sandbox Code Playgroud)

如果你传递第三个参数为true,你会得到IllegalStateException,因为这个人.

getSupportFragmentManager()
      .beginTransaction()
      .add(parent, childFragment)
      .commit();
Run Code Online (Sandbox Code Playgroud)

因为您已经错误地在onCreateView()中添加了子片段.调用add将告诉您子视图已添加到父类因此IllegalStateException.
这里你不负责添加childView,FragmentManager负责.所以在这种情况下总是传递假.

注意:我还读过如果attachToRoot为false,则parentView将不会获取childView touchEvents.但我还没有测试过它.

  • 非常有帮助,尤其是关于`FragmentManager`的部分,谢谢! (2认同)
  • 解释得很好。这应该是 Android 文档的一部分。当我阅读 android 文档时我并不清楚 (2认同)

Jos*_*arl 92

如果设置为true,那么当布局膨胀时,它将自动添加到第二个参数中指定的ViewGroup的视图层次结构中作为子项.例如,如果根参数是a,LinearLayout那么您的膨胀视图将自动添加为该视图的子视图.

如果设置为false,那么您的布局将会膨胀,但不会附加到任何其他布局(因此不会绘制,接收触摸事件等).

  • 因为Fragment会自动附加从onCreateView返回的布局.因此,如果您在onCreateView中手动附加它,那么您的视图将附加到2个父项(这会产生您提到的错误). (65认同)
  • 我糊涂了.在我读到[这个答案](http://stackoverflow.com/a/6036484/403455)之前我得到了一个"指定的孩子已经有一个父错误",这导致我在我的'attachToRoot`中使用`false`片段的'onCreateView`.这解决了问题,但片段的布局是可见的和活跃的,尽管你的答案.这里发生了什么? (16认同)
  • 我在这里有点困惑,@ JoosephEarl你说如果设置为`true`,视图附加到第二个参数,即`容器`,但是你说片段是从`onCreateView()`自动附加的,所以到我的理解,第三个参数是无用的,应该总是设置`false`? (10认同)
  • @unmultimedio它只对`onCreateView`返回的根视图没用.如果您将更多布局扩展到该根视图中,或者您在不同的上下文中膨胀(例如在活动中),则它很有用. (6认同)
  • 您在oncreateview中返回视图,然后自动附加.如果将attach设置为true,则会引发错误.但是,在独立情况下展开视图时,可以选择通过设置为true将视图自动附加到其容器.我几乎没有设置为真,因为我总是自己添加视图. (4认同)

Mar*_*res 36

看起来像响应中的很多文本但没有代码,这就是为什么我决定用一个代码示例重新回答这个旧问题,在人们提到的几个回复中:

如果设置为true,那么当布局膨胀时,它将自动添加到第二个参数中指定的ViewGroup的视图层次结构中作为子项.

这在代码中实际意味着什么(大多数程序员都理解):

public class MyCustomLayout extends LinearLayout {
    public MyCustomLayout(Context context) {
        super(context);
        // Inflate the view from the layout resource and pass it as child of mine (Notice I'm a LinearLayout class).

        LayoutInflater.from(context).inflate(R.layout.child_view, this, true);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,之前的代码是因为param 而将布局添加R.layout.child_view为子级,并且以与编程方式相同的方式分配父级的布局参数,或者就像我在xml中执行此操作一样:MyCustomLayoutattachToRoottrueaddView

<LinearLayout>
   <View.../>
   ...
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

下面的代码经过时解释情况attachRootfalse:

LinearLayout linearLayout = new LinearLayout(context);
linearLayout.setLayoutParams(new LayoutParams(
    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
linearLayout.setOrientation(LinearLayout.VERTICAL);
    // Create a stand-alone view
View myView = LayoutInflater.from(context)
    .inflate(R.layout.ownRootView, null, false);
linearLayout.addView(myView);
Run Code Online (Sandbox Code Playgroud)

在前面的代码中,您指定您希望myView成为它自己的根对象,并且不将它附加到任何父对象,稍后我们将其作为其中的一部分添加它,LinearLayout但暂时它是一个独立的(没有父对象)视图.

Fragments也会发生同样的事情,您可以将它们添加到已存在的组中并成为其中的一部分,或者只传递参数:

inflater.inflate(R.layout.fragment,null,false);

指定它将是它自己的根.


Luk*_*rog 26

文档和前两个答案应该足够了,只是我的一些想法.

inflate方法用于膨胀布局文件.使用这些夸大的布局,您必须可以将它们直接附加到父级,ViewGroup或者只是从该布局文件中扩展视图层次结构,并在普通视图层次结构之外使用它.

在第一种情况下,attachToRoot必须将参数设置为true(或者很简单地使用inflate采用布局文件和父根ViewGroup(非null)的方法).在这种情况下,View返回的只是ViewGroup在方法中传递的ViewGroup内容,膨胀的视图层次结构将添加到该方法中.

对于第二个选项,返回的ViewViewGroup布局文件中的根.如果你还记得我们在include-merge配对问题中的最后一次讨论,这就是merge限制的原因之一(当mergeroot作为布局文件膨胀时,你必须提供父,attachedToRoot必须设置为true).如果你有一个带有merge标签的布局文件,并且attachedToRoot设置为,false则该inflate方法将没有任何内容可以返回,因为merge没有等效项.此外,正如文档所述inflate,attachToRoot设置为的版本false很重要,因为您可以使用LayoutParams父项中的正确创建视图层次结构.这在某些情况下很重要,最值得注意的AdapterView是子类的子元素ViewGroup,addView()不支持方法集.我确定你记得在这个getView()方法中使用这一行:

convertView = inflater.inflate(R.layout.row_layout, parent, false);
Run Code Online (Sandbox Code Playgroud)

此行确保膨胀R.layout.row_layout文件的根目录中设置LayoutParamsAdapterView子类正确ViewGroup.如果你不这样做,你可能会遇到布局文件的一些问题,如果root是a RelativeLayout.它TableLayout/TableRow也有一些特殊和重要的LayoutParams,你应该确保它们中的视图是正确的LayoutParams.


Ume*_*ooq 18

我自己也搞不清楚什么是真正的目的attachToRootinflate方法.经过一些UI研究后,我终于得到了答案:

父:

在这种情况下,是使用findViewById()围绕要扩充的视图对象的窗口小部件/布局.

attachToRoot:

将视图附加到其父级(包括它们在父级层次结构中),因此视图接收的任何触摸事件也将转移到父视图.现在,它是由父母决定是否要接受这些事件或忽略它们.如果设置为false,则不会将它们添加为父项的直接子项,并且父项不会从视图中接收任何触摸事件.

希望这清除了混乱


sea*_*ell 9

由于inflate()方法的文档,这个主题存在很多混淆.

通常,如果attachToRoot设置为true,则第一个参数中指定的布局文件会膨胀并附加到此时第二个参数中指定的ViewGroup.当attachToRoot为false时,第一个参数的布局文件会膨胀并作为View返回,并且任何View附件都会在其他时间发生.

除非你看到很多例子,否则这可能并不重要.在Fragment的onCreateView方法内部调用LayoutInflater.inflate()时,您需要为attachToRoot传入false,因为与该Fragment关联的Activity实际上负责添加Fragment的视图.如果您在稍后的某个时间点手动充气并将视图添加到另一个视图,例如使用addView()方法,则需要为attachToRoot传入false,因为附件会在稍后的时间点传递.

您可以在我撰写的有关此主题的博客文章中阅读有关对话框和自定义视图的其他几个独特示例.

https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/


cap*_*wag 8

我写了这个答案,因为即使经过几个StackOverflow页面,我也无法清楚地了解attachToRoot的含义.下面是LayoutInflater类中的inflate()方法.

View inflate (int resource, ViewGroup root, boolean attachToRoot)
Run Code Online (Sandbox Code Playgroud)

看一下activity_main.xml文件,button.xml布局和我创建的MainActivity.java文件.

activity_main.xml中

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

button.xml

<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
Run Code Online (Sandbox Code Playgroud)

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    LayoutInflater inflater = getLayoutInflater();
    LinearLayout root = (LinearLayout) findViewById(R.id.root);
    View view = inflater.inflate(R.layout.button, root, false);
}
Run Code Online (Sandbox Code Playgroud)

当我们运行代码时,我们将看不到布局中的按钮.这是因为我们的按钮布局未添加到主活动布局中,因为attachToRoot设置为false.

LinearLayout有一个addView(视图)方法,可用于将视图添加到LinearLayout.这会将按钮布局添加到主活动布局中,并在运行代码时使按钮可见.

root.addView(view);
Run Code Online (Sandbox Code Playgroud)

让我们删除上一行,看看当我们将attachToRoot设置为true时会发生什么.

View view = inflater.inflate(R.layout.button, root, true);
Run Code Online (Sandbox Code Playgroud)

我们再次看到按钮布局是可见的.这是因为attachToRoot直接将膨胀的布局附加到指定的父级.在这种情况下,根LinearLayout.在这里,我们不必像在前一种情况下使用addView(View view)方法那样手动添加视图.

为片段设置attachToRoot为true时,为什么人们会收到IllegalStateException.

这是因为对于片段,您已经指定了将片段布局放在活动文件中的位置.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .add(R.id.root, fragment)
    .commit();
Run Code Online (Sandbox Code Playgroud)

插件(INT父母,片段片段)增加了它有它的布局父布局的片段.如果我们将attachToRoot设置为true,您将获得IllegalStateException:指定的子节点已经有父节点.由于片段布局已添加到add()方法中的父布局中.

在对片段进行充气时,应始终为attachToRoot传递false.FragmentManager的工作是添加,删除和替换Fragments.

回到我的例子.如果我们两个都做了怎么办

View view = inflater.inflate(R.layout.button, root, true);
root.addView(view);
Run Code Online (Sandbox Code Playgroud)

在第一行中,LayoutInflater将按钮布局附加到根布局,并返回一个包含相同按钮布局的View对象.在第二行中,我们将相同的View对象添加到父根布局.这导致我们在Fragments中看到的IllegalStateException(指定的子节点已经有父节点).

请记住,还有另一个重载的inflate()方法,默认情况下将attachToRoot设置为true.

View inflate (int resource, ViewGroup root)
Run Code Online (Sandbox Code Playgroud)

  • 这是这里唯一的答案,解释了省略时“attachToRoot”默认设置为“true”(这是违反直觉的) (2认同)

Als*_*ton 5

attachToRoot设置为 true 意味着inflatedView将添加到父视图的层次结构中。因此可能被用户“看到”并感知触摸事件(或任何其他 UI 操作)。否则,它只是被创建,没有被添加到任何视图层次结构中,因此无法被看到或处理触摸事件。

对于刚接触 Android 的 iOS 开发人员来说,attachToRoot设置为 true 意味着您调用此方法:

[parent addSubview:inflatedView];
Run Code Online (Sandbox Code Playgroud)

如果更进一步,您可能会问:如果我设置为 ,为什么要传递父attachToRoot视图false?这是因为 XML 树中的根元素需要父视图来计算一些 LayoutParams(例如匹配父级)。


Cas*_*eyB 0

当您定义父级时,attachToRoot 确定您是否希望充气器将其实际附加到父级。在某些情况下,这会导致问题,例如在 ListAdapter 中,它会导致异常,因为列表尝试将视图添加到列表中,但它说它已经附加。在其他情况下,您只是自己膨胀视图以添加到活动中,这可能会很方便并为您节省一行代码。

  • 没有给出一个好的答案应该提供的清晰图片。 (2认同)