LayoutInflater。膨胀文档对我来说并不完全清楚attachtorroot参数的用途。

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

有没有人能更详细地解释一下,具体地说,根视图是什么,也许还能举个例子,说明在真值和假值之间的行为变化?


当前回答

我自己也很困惑膨胀方法中attachtorroot的真正目的是什么。在研究了一些UI后,我终于得到了答案:

家长:

在本例中是围绕视图对象的小部件/布局,您希望使用findViewById()进行膨胀。

attachToRoot:

将视图附加到它们的父视图(将它们包含在父层次结构中),因此视图接收到的任何触摸事件也将被转移到父视图。现在,由父母决定是要接受这些事件还是忽略它们。如果设置为false,它们不会作为父节点的直接子节点被添加,父节点也不会从视图中接收任何触摸事件。

希望这能澄清困惑

其他回答

回复中似乎有很多文本,但没有代码,这就是为什么我决定用一个代码示例来恢复这个老问题,在几个回复中人们提到:

如果设置为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);
    }
}

注意,前面的代码添加了布局R.layout。child_view作为MyCustomLayout的孩子,因为attachToRoot参数为真,并以完全相同的方式分配父布局参数,如果我将使用addView编程,或如果我在xml中这样做:

LinearLayout < > <视图…/ > ... LinearLayout < / >

下面的代码解释了当传递attachRoot为false时的场景:

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);

在前面的代码中,你指定你想要myView是它自己的根对象,不附加到任何父对象,后来我们将它添加为LinearLayout的一部分,但暂时它是一个独立的(没有父)视图。

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

inflater. inflation (r.b ayout.fragment, null, false);

来指定它将是它自己的根。

我自己也很困惑膨胀方法中attachtorroot的真正目的是什么。在研究了一些UI后,我终于得到了答案:

家长:

在本例中是围绕视图对象的小部件/布局,您希望使用findViewById()进行膨胀。

attachToRoot:

将视图附加到它们的父视图(将它们包含在父层次结构中),因此视图接收到的任何触摸事件也将被转移到父视图。现在,由父母决定是要接受这些事件还是忽略它们。如果设置为false,它们不会作为父节点的直接子节点被添加,父节点也不会从视图中接收任何触摸事件。

希望这能澄清困惑

我写这个答案是因为即使在浏览了几个StackOverflow页面后,我也不能清楚地理解attachtorroot的意思。下面是LayoutInflater类中的inflation()方法。

View inflate (int resource, ViewGroup root, boolean attachToRoot)

看一下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>

button.xml

<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

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);
}

当我们运行代码时,我们不会在布局中看到按钮。这是因为我们的按钮布局没有添加到主活动布局中,因为attachtorroot被设置为false。

线性布局有一个addView(视图视图)方法,可以用来添加视图到线性布局。这将把按钮布局添加到主活动布局中,并在运行代码时使按钮可见。

root.addView(view);

让我们删除前一行,看看当我们将attachtorroot设置为true时会发生什么。

View view = inflater.inflate(R.layout.button, root, true);

我们再次看到按钮布局是可见的。这是因为attachtorroot直接将膨胀布局附加到指定的父布局上。这里是根LinearLayout。在这里,我们不需要像之前使用addView(View View)方法那样手动添加视图。

为什么人们得到IllegalStateException当设置一个片段的attachtorroot为真。

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

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .add(R.id.root, fragment)
    .commit();

add(int parent, Fragment Fragment)将拥有自己布局的片段添加到父布局中。如果我们将attachtorroot设置为true,你将得到IllegalStateException:指定的子已经有一个父。因为片段布局已经在add()方法中添加到父布局中。

当你在膨胀fragment时,你应该总是为attachtorroot传递false。添加、删除和替换片段是FragmentManager的工作。

回到我的例子。如果我们两者都做呢?

View view = inflater.inflate(R.layout.button, root, true);
root.addView(view);

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

请记住,还有另一个重载的inflation()方法,它在默认情况下将attachtorroot设置为true。

View inflate (int resource, ViewGroup root)

现在与否

“第三个”参数attachtorroot是真还是假的主要区别是这样的。

当你输入attachtorroot

true:立即将子视图添加到父视图 false:现在将子视图添加到父视图。 稍后再添加。`

什么时候?

后面就是使用parent。addview (childView)

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

inflater.inflate(child,parent,false);
parent.addView(child);   

等于

inflater.inflate(child,parent,true);

一个大禁忌 当您不负责将子视图添加到父视图时,永远不要将attachtorroot传递为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;
  }

如果你传递第三个参数为true,你会得到IllegalStateException,因为这个家伙。

getSupportFragmentManager()
      .beginTransaction()
      .add(parent, childFragment)
      .commit();

因为你已经在onCreateView()中错误地添加了子片段,调用add会告诉你子视图已经添加到父视图,因此IllegalStateException。 这里你不负责添加childView, FragmentManager负责。这里总是传递false。

注意:我还读到,如果attachtorroot为false, parentView将不会获得childView touchEvents。但我还没有测试过。

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

对于刚接触Android的iOS开发者,attachtorroot设置为true意味着你调用这个方法:

[parent addSubview:inflatedView];

如果更进一步,你可能会问:如果我将attachtorroot设置为false,为什么我要传递父视图?这是因为XML树中的根元素需要父视图来计算一些LayoutParams(比如match parent)。