我动态添加和删除视图到自定义视图(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调用。 有谁知道为什么会产生影响?
答案 0 :(得分:15)
答案在于此次电话会议
mMyView = inflater.inflate(resId, this, true);
文档说明:
返回膨胀层次结构的根视图。如果提供了root 而attachToRoot为true,这是root;否则它是根的 膨胀的XML文件。
我假设膨胀调用总是返回膨胀布局的根(由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()