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


138

首先一点背景:

我在scrollview中有一个布局。首先,当用户在屏幕上滚动时,滚动视图将滚动。但是,经过一定数量的滚动后,我将禁用滚动视图上的滚动,将“滚动焦点”移到子布局内的Web视图上。这样,滚动视图会停留,所有滚动事件都将进入其中的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-> scrollview-> 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。

Answers:


289

解:

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

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

感谢@Dongshengcn提供的解决方案


1
解决方案是正确的,但是为什么“ scollView.removeView(scrollChildLayout)”不起作用?这两行不应该相同吗?
andrea.rinaldi 2014年

@ andrea.spot,似乎scrollView.removeView(scrollChildLayout)试图删除scrollView的子级,而不是从其父级ViewGroup中删除scrollView本身
Dmitry Gryazin 2014年

1
@ user25我知道这对于您来说可能为时已晚,但空指针异常是由于父级为空,这意味着视图未附加到任何父级。由于开始时没有父母,因此没有任何要删除的内容。 if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView);
Tarek

@kasgoku能帮我吗?我试图在单击按钮时以相对布局显示片段。但显示错误“指定的子代已经有一个父代。您必须首先在子代的父代上调用removeView()。” 如何解决呢?
Imranrana19年

在聊天应用程序之一的应用程序中,我也收到此错误。我正在尝试解决这个问题。该图标已删除,但我需要再次使用该图标上传图像。(stackoverflow.com/q/58117428/10971384)这是我的问题链接
Thangapandi

21

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

scrollview.removeView(scrollChildLayout)

或从父视图中删除所有子项,然后再次添加它们。

scrollview.removeAllViews()

我已经在上面的问题中的代码中调用了removeView。removeAllViews()也不起作用。
kasgoku 2011年

您确定它是您正在调用removeView()/ removeAllViews()的父级吗?我在做非常类似的事情,它一直在为我工作。
dongshengcn

4
您可以通过查看以下内容来查看其父项:view.getParent()developer.android.com/reference/android/view/…–
dongshengcn

@dongshengcn您能帮我吗?我试图在单击按钮时以相对布局显示片段。但显示错误“指定的子代已经有一个父代。您必须首先在子代的父代上调用removeView()。” 如何解决呢?
Imranrana19年

19

在带有活动的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) {

}

15

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

  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界面的一部分。当一个完美合适的接口可用时,不应该将其转换为具体的类。


3

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


没用 这就是我尝试的方法:scrollView.removeView(scrollChildLayout); scrollView.setVisibility(View.GONE); parentLayout.post(new Runnable(){@Override public void run(){parentLayout.addView(scrollChildLayout);}});
kasgoku 2011年

1

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

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

另外,您不应该使用View.GONE删除视图。如果确实删除了它,那么您将不需要隐藏它,否则它仍然存在并且您只是对自己隐藏了:(


1

就我而言,我有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();
}

您是否尝试过选择下一个片段并按得太快?
iamthevoid

1

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)
}

0

您也可以通过检查View的indexOfView方法(如果indexOfView方法返回-1)来执行此操作。

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


0

我在做错什么,所以我得到了这个错误是我没有实例化动态布局并向其添加子元素,所以得到了这个错误


0

这是我的解决方案。

假设您有两个,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足够了。

否则这里是孤独:

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());
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.