LayoutInflater。膨胀文档对我来说并不完全清楚attachtorroot参数的用途。
attachtorroot:膨胀的层次结构是否应该附加到根参数?如果为false,则root仅用于创建正确的 XML中根视图的LayoutParams的子类。
有没有人能更详细地解释一下,具体地说,根视图是什么,也许还能举个例子,说明在真值和假值之间的行为变化?
LayoutInflater。膨胀文档对我来说并不完全清楚attachtorroot参数的用途。
attachtorroot:膨胀的层次结构是否应该附加到根参数?如果为false,则root仅用于创建正确的 XML中根视图的LayoutParams的子类。
有没有人能更详细地解释一下,具体地说,根视图是什么,也许还能举个例子,说明在真值和假值之间的行为变化?
当前回答
我写这个答案是因为即使在浏览了几个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)。
如果设置为true,那么当你的布局膨胀时,它将自动添加到ViewGroup的视图层次结构中,在第二个参数中指定作为子参数。例如,如果根参数是线性布局,那么你的膨胀视图将自动添加为该视图的子视图。
如果它被设置为false,那么你的布局将被膨胀,但不会附加到任何其他布局(所以它不会被绘制,接收触摸事件等)。
例如我们有一个ImageView,一个LinearLayout和一个RelativeLayout。LinearLayout是RelativeLayout的子元素。 视图层次结构将是。
RelativeLayout
------->LinearLayout
我们有一个单独的ImageView布局文件
image_view_layout.xml
附根:
//here container is the LinearLayout
View v = Inflater.Inflate(R.layout.image_view_layout,container,true);
这里v包含了容器布局的引用,即 LinearLayout。如果你想设置setImageResource(R.drawable.np)等参数;你必须通过父类的引用来找到它,即view.findById() v的父元素是FrameLayout。 LayoutParams将属于FrameLayout。
不连接到根:
//here container is the LinearLayout
View v = Inflater.Inflate(R.layout.image_view_layout,container,false);
这里v包含的不是参考容器布局,而是直接布局 ImageView的引用是膨胀的,所以你可以设置它的 参数如view.setImageResource(R.drawable.np);没有 引用像findViewById。但是容器被指定了 ImageView获取容器的LayoutParams,你可以说 container的引用只是为了LayoutParams什么都没有 其他的事情。 所以在特定情况下Parent将为null。 LayoutParams将属于LinearLayout。
我自己也很困惑膨胀方法中attachtorroot的真正目的是什么。在研究了一些UI后,我终于得到了答案:
家长:
在本例中是围绕视图对象的小部件/布局,您希望使用findViewById()进行膨胀。
attachToRoot:
将视图附加到它们的父视图(将它们包含在父层次结构中),因此视图接收到的任何触摸事件也将被转移到父视图。现在,由父母决定是要接受这些事件还是忽略它们。如果设置为false,它们不会作为父节点的直接子节点被添加,父节点也不会从视图中接收任何触摸事件。
希望这能澄清困惑