首先在孩子的父母上调用 removeView()

Posted

技术标签:

【中文标题】首先在孩子的父母上调用 removeView()【英文标题】:Call removeView() on the child's parent first 【发布时间】:2011-09-25 11:51:05 【问题描述】:

先介绍一点背景:

我在滚动视图中有一个布局。起初,当用户在屏幕上滚动时,滚动视图滚动。但是,经过一定量的滚动后,我要禁用滚动视图上的滚动,将“滚动焦点”移动到子布局内的 web 视图上。这样,scrollview 会粘住,所有的滚动事件都会转到里面的 webview。

因此,对于一个解决方案,当达到滚动阈值时,我从滚动视图中删除子布局并将其放在滚动视图的父级中。(并使滚动视图不可见)。

// Remove the child view from the scroll view
scrollView.removeView(scrollChildLayout);

// Get scroll view out of the way
scrollView.setVisibility(View.GONE);

// Put the child view into scrollview's parent view
parentLayout.addView(scrollChildLayout);

总体思路:(-> 表示包含)

之前:父布局 -> 滚动视图 -> 滚动子布局

之后:parentLayout -> scrollChildLayout

上面的代码给了我这个异常:

java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
           at android.view.ViewGroup.addViewInner(ViewGroup.java:1976)
           at android.view.ViewGroup.addView(ViewGroup.java:1871)
           at android.view.ViewGroup.addView(ViewGroup.java:1828)
           at android.view.ViewGroup.addView(ViewGroup.java:1808)

你知道发生了什么吗?我显然是在父级上调用 removeView。

【问题讨论】:

【参考方案1】:

尝试先从其父视图中移除 scrollChildLayout?

scrollview.removeView(scrollChildLayout)

或者从父视图中删除所有子视图,然后重新添加。

scrollview.removeAllViews()

【讨论】:

我已经在上面问题的代码中调用了 removeView 。 removeAllViews() 也不起作用。 你确定它是你调用 removeView()/removeAllViews() 的父级吗?我正在做非常相似的事情,它一直在为我工作。 您可以通过以下方式查看其父级:view.getParent() developer.android.com/reference/android/view/… @dongshengcn 你能帮帮我吗?我试图在单击按钮时以相对布局显示片段。但它显示错误“指定的孩子已经有一个父母。您必须首先在孩子的父母上调用 removeView()。”如何解决这个问题?【参考方案2】:

您所要做的就是 post() 一个执行 addView() 的 Runnable。

【讨论】:

没用。这就是我尝试过的:scrollView.removeView(scrollChildLayout); scrollView.setVisibility(View.GONE); parentLayout.post(new Runnable() @Override public void run() parentLayout.addView(scrollChildLayout); );【参考方案3】:

解决方案:

((ViewGroup)scrollChildLayout.getParent()).removeView(scrollChildLayout);
//scrollView.removeView(scrollChildLayout);

使用子元素获取对父元素的引用。将父级强制转换为 ViewGroup,以便您可以访问 removeView 方法并使用它。

感谢@Dongshengcn的解决方案

【讨论】:

解决方案是对的,但为什么“scollView.removeView(scrollChildLayout)”不起作用呢?这两行不应该一样吗? @andrea.spot,好像scrollView.removeView(scrollChildLayout) 试图删除scrollView 的子项,而不是从其父ViewGroup 中删除scrollView 本身 @user25 我知道这对你来说可能为时已晚,但空指针异常是由于父级为空,这意味着视图未附加到任何父级。因为一开始没有父母,所以没有什么可以删除的。 if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView); @kasgoku 你能帮帮我吗?我试图在单击按钮时以相对布局显示片段。但它显示错误“指定的孩子已经有一个父母。您必须首先在孩子的父母上调用 removeView()。”如何解决这个问题? 我在聊天应用程序之一的应用程序中也遇到了这个错误。我正在尝试解决这个问题。该图标已删除,但我需要再次使用该图标来上传图像。 (***.com/q/58117428/10971384)这是我的问题链接【参考方案4】:

你也可以通过检查 View 的 indexOfView 方法来做到这一点 如果 indexOfView 方法返回 -1 则我们可以使用。

ViewGroup 的 detachViewFromParent(v); 其次是 ViewGroup 的 removeDetachedView(v, true/false);

【讨论】:

【参考方案5】:

好吧,叫我偏执狂,但我建议:

  final android.view.ViewParent parent = view.getParent ();

  if (parent instanceof android.view.ViewManager)
  
     final android.view.ViewManager viewManager = (android.view.ViewManager) parent;

     viewManager.removeView (view);
   // if

没有instanceof 的投射似乎是错误的。并且(感谢 IntelliJ IDEA 告诉我)removeViewViewManager 接口的一部分。当一个完全合适的接口可用时,不应强制转换为具体类。

【讨论】:

【参考方案6】:

我正在调用 parentView.removeView(childView) 并且 childView 仍在显示。我最终意识到一个方法以某种方式被触发了两次,并将 childView 添加到 parentView 两次。

因此,在添加视图之前和之后,使用 parentView.getChildCount() 来确定父级有多少个子级。如果子项添加的次数过多,则最上面的子项将被删除,并且副本 childView 仍然存在 - 即使它是,removeView 看起来也可以正常工作。

另外,您不应该使用 View.GONE 来删除视图。如果它真的被移除了,那么你就不需要隐藏它,否则它仍然存在,你只是对自己隐藏它:(

【讨论】:

【参考方案7】:

在带有活动的 onCreate 中或带有片段的 onCreateView 中。

 if (view != null) 
    ViewGroup parent = (ViewGroup) view.getParent();
    if (parent != null) 
        parent.removeView(view);
    

try 
    view = inflater.inflate(R.layout.fragment_main, container, false);
 catch (InflateException e) 


【讨论】:

【参考方案8】:

我做错了什么所以我得到这个错误是我没有实例化动态布局并添加孩子所以得到这个错误

【讨论】:

【参考方案9】:

就我而言,我有 BaseFragment 和所有其他片段都继承自此。

所以我的解决方法是在 OnDestroyView() 方法中添加这一行

@Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)

    if (mRootView == null)
    
        mRootView = (inflater == null ? getActivity().getLayoutInflater() : inflater).inflate(mContentViewResourceId, container, false);
    
....////


@Override
public void onDestroyView()

    if (mRootView != null)
    
        ViewGroup parentViewGroup = (ViewGroup) mRootView.getParent();

        if (parentViewGroup != null)
        
            parentViewGroup.removeAllViews();
        
    

    super.onDestroyView();

【讨论】:

您是否尝试过选择下一个片段并按回太快?【参考方案10】:

这是我的解决方案。

假设您有两个TextViews,并将它们放在LinearLayout(命名为ll)上。您将把这个LinerLayout 放在另一个LinerLayout 上。

< lm Linear Layout> 
       < ll Linear Layout> 
             <name Text view>
             </name Text view>
             <surname Text view>
             </surname Text view>
       </ll Linear Layout> 
</lm Linear Layout> 

当您想要创建此结构时,您需要将父级作为继承。

如果你想在 onCreate 方法中使用它,this 就足够了。

否则这里是solition:

LinerLayout lm = new LinearLayout(this); // You can use getApplicationContext() also
LinerLayout ll = new LinearLayout(lm.getContext());
TextView name = new TextView(ll.getContext());
TextView surname = new TextView(ll.getContext());

【讨论】:

【参考方案11】:

Kotlin 解决方案

Kotlin 使用 as? 简化父级转换,如果左侧为 null 或转换失败,则返回 null。

(childView.parent as? ViewGroup)?.removeView(childView)

Kotlin 扩展解决方案

如果您想进一步简化,可以添加此扩展。

childView.removeSelf()

fun View?.removeSelf() 
    this ?: return
    val parentView = parent as? ViewGroup ?: return
    parentView.removeView(this)

如果此 View 为 null、父视图为 null 或父视图不是 ViewGroup,它不会安全地执行任何操作

注意:如果您还希望父级安全删除子视图,请添加以下内容:

fun ViewGroup.removeViewSafe(toRemove: View) 
    if (contains(toRemove)) removeView(toRemove)

【讨论】:

这个答案没有对这个问题提供任何实际的解释。

以上是关于首先在孩子的父母上调用 removeView()的主要内容,如果未能解决你的问题,请参考以下文章

首先在孩子的父母上调用 removeView()

收到错误“您必须首先在孩子的父母上调用removeView()”

我继续收到错误消息“指定的孩子已经有一个父母。您必须首先在该孩子的父母上调用removeView()(Android)

收到错误“指定的孩子已经有父母。您必须先在孩子的父母上调用 removeView()。”? [复制]

指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()

Fragments - 指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()