【问题标题】:removeView not working after LayoutInflater.inflate(resource, root, true)在 LayoutInflater.inflate(resource, root, true) 之后 removeView 不起作用
【发布时间】:2013-12-24 05:29:22
【问题描述】:

我这样做是动态地向自定义视图 (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 调用来完成。 有谁知道为什么这会有所作为?

【问题讨论】:

    标签: android view viewgroup


    【解决方案1】:

    答案就在这个电话里

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

    文档说明:

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

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

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

    所以当

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

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

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

    分配该视图的父级。调用 removeView(mMyView) 实际上与 removeView(this) 相同,显然没有任何作用。

    这种行为在 IMO 中非常违反直觉并且容易出错。当我们已经有了带有 root 参数的根布局而我们还没有对膨胀布局的引用时,为什么要返回根布局而不是膨胀布局?

    【讨论】:

    • 4 年过去了,同样愚蠢的 Android API 决策仍然在绊倒人们。感谢您的回答。
    • 感谢提醒 :) 在仔细阅读文档后不久我就知道了这一点,但最近在不记得原因的情况下遇到了这个问题。感谢您的帖子,您为我节省了一些时间!
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

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

      希望它对你有用。

      【讨论】:

      • 是否明确提供 LayoutParams 或使用根布局提供的那些与问题无关。此外,使用 getParent() 只会返回与“this”相同的自定义 FrameLayout,并且执行 ((MyCustomFrameLayout)mMyView.getParent()).removeView(mMyView) 与 removeView(mMyView) 相同,至少如果 mMyView 实际上是添加到自定义 FrameLayout (它不是,但由于你没有在你的答案中解释的原因)。
      【解决方案4】:

      如果您使用的是列表视图,您是否尝试在删除后使其失效。

      ListView.invalidate()
      

      【讨论】:

      • 添加视图发生在列表适配器的 getView() 方法中,因此在创建要显示的视图时。使列表视图无效可能会导致无限循环...
      • 你是否将 removeView 放入 getView() 中?
      • 好的,我明白你的意思了。单击列表项中的按钮时,视图将被删除。我在删除视图后添加了一个无效但没有任何变化。
      猜你喜欢
      • 2015-08-13
      • 1970-01-01
      • 2015-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多