在LayoutInflater.inflate(resource,root,true)之后removeView无法正常工作

时间:2013-12-06 18:31:37

标签: android view viewgroup

我动态添加和删除视图到自定义视图(FrameLayout)执行此操作:

LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mMyView = inflater.inflate(resId, this, true);

稍后我尝试删除视图,但视图不会删除:

removeView(mMyView);

如果我这样做,一切都按预期工作:

mMyView = inflater.inflate(resId, this, **false**);
addView(mMyView);

唯一的区别是我手动添加视图而不是让inflate调用。 有谁知道为什么会产生影响?

4 个答案:

答案 0 :(得分:15)

答案在于此次电话会议

mMyView = inflater.inflate(resId, this, true);

文档说明:

  

返回膨胀层次结构的根视图。如果提供了root   而attachToRoot为true,这是root;否则它是根的   膨胀的XML文件。

http://developer.android.com/reference/android/view/LayoutInflater.html#inflate(int, android.view.ViewGroup, boolean)

我假设膨胀调用总是返回膨胀布局的根(由resId定义),但如果提供了root参数且attachToRoot为true,那么它是布局的根,膨胀布局被添加到(它的新父级)视图)和那个根(在这种情况下,root == this)。

所以,而

mMyView = inflater.inflate(resId, this, false);

将视图分配给我们想要稍后删除的mMyView

mMyView = inflater.inflate(resId, this, true);

指定该视图的父级。调用removeView(mMyView)实际上与removeView(this)相同,显然没有做任何事情。

此行为是IMO非常反直觉并且容易出错。当我们已经使用root参数的根布局时,为什么它应该返回根布局而不是膨胀布局,而我们还没有对膨胀布局的引用呢?

答案 1 :(得分:2)

根据我的经验,这取决于您在何处创建对传递给inflate(...)调用的父视图的引用。我一直在你的情况下(即使它不应该失败,有时如果我们不从正确的地方调用它)我已经证明在代码中创建自定义视图,设置更好LayoutParams也是以编程方式编写的。从文档中可以推断出,主ViewGroup主要用于获取布局参数。 因此,在您使用'false'进行膨胀之后,您可以构建自己的FrameLayout.LayoutParams,使用它们提供膨胀的视图,然后将视图添加到父级。 您可能还想尝试而不是直接从自定义布局中删除视图,调用View.getParent(),将其转换为自定义FrameLayout,然后从转换结果中调用removeView(...)。

   ((MyCustomFrameLayout)mMyView.getParent()).removeView(mMyView); 

出于调试目的(当您使用'true'时),您可以检查膨胀视图的结果父级(以及子级本身)是否与传递给原始调用的父级相同。也许它们会在代码中的某个时刻发生变化(或引用丢失)。

希望它适合你。

答案 2 :(得分:2)

似乎在较新的Android版本中,布局转换可能会延迟删除视图,要么将调用延迟到addView(),要么使用parent.setLayoutTransition(null)

答案 3 :(得分:1)

如果您使用列表视图,请在删除后尝试使其无效。

ListView.invalidate()