145

First a little background:

I have a layout inside a scrollview. At first, when the user scrolls on the screen, the scrollview scrolls. However, after a certain amount of scroll, I was to disable the scroll on the scroll view the move the "scroll focus" onto a webview inside the child layout. This way, the scrollview sticks and all the scroll events go to the webview inside it.

So, for a solution, when the scroll threshold is reached, I remove the child layout from the scrollview and put it in scrollview's parent.(And make the scrollview invisible).

// 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);

General Idea: (-> means contains)

Before: parentlayout -> scrollview -> scrollChildLayout

After : parentLayout -> scrollChildLayout

The above code is giving me this exception:

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)

Do you know what's going on? I am clearly calling removeView on the parent.

ForceMagic
  • 6,230
  • 12
  • 66
  • 88
kasgoku
  • 5,057
  • 5
  • 20
  • 20

11 Answers11

294

Solution:

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

Use the child element to get a reference to the parent. Cast the parent to a ViewGroup so that you get access to the removeView method and use that.

Thanks to @Dongshengcn for the solution

kasgoku
  • 5,057
  • 5
  • 20
  • 20
  • 1
    The solution is right, but why "scollView.removeView(scrollChildLayout)" wouldn't work? Shouldn't the two lines be the same? – andrea.rinaldi Jun 27 '14 at 08:40
  • @andrea.spot, seems like `scrollView.removeView(scrollChildLayout)` tries to remove the child of scrollView, not to remove the scrollView itself from its parent ViewGroup – Dmitry Gryazin Jul 11 '14 at 12:12
  • 1
    @user25 i know this maybe too late for u but the null pointer exception is due to the parent being empty meaning the view is not attached to any parent. since there is no parent at the beginning, there is nothing to remove. `if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView);` – Tarek Sep 08 '16 at 19:46
  • @kasgoku can you help me please. i am trying to show a fragment in relative layout on a button click. but its showing error "The specified child already has a parent. You must call removeView() on the child's parent first." how to solve this? – im07 Apr 10 '19 at 11:22
  • I also got this error in my application that is one of the chat application. I am trying to solve this problem. that icon is removed but I need the icon again for uploading images. ( https://stackoverflow.com/q/58117428/10971384 ) this is my question link – Thangapandi Sep 27 '19 at 05:54
  • Btw i have fragment but i don't have scrolling view so how can i get solution getting same error – Pankaj Gadhiya Nov 18 '19 at 08:05
22

Try remove scrollChildLayout from its parent view first?

scrollview.removeView(scrollChildLayout)

Or remove all the child from the parent view, and add them again.

scrollview.removeAllViews()
dongshengcn
  • 6,434
  • 7
  • 35
  • 44
  • I am already calling removeView in the code in my question above. removeAllViews() doesn't work either. – kasgoku Jun 29 '11 at 21:16
  • Are you sure it is the parent you are calling removeView()/removeAllViews()? I am doing very similar thing, and it has been working for me. – dongshengcn Jun 30 '11 at 13:47
  • 4
    You can look at its parent by looking at: view.getParent() http://developer.android.com/reference/android/view/View.html#getParent() – dongshengcn Jun 30 '11 at 13:49
  • @dongshengcn can you help me please. i am trying to show a fragment in relative layout on a button click. but its showing error "The specified child already has a parent. You must call removeView() on the child's parent first." how to solve this? – im07 Apr 10 '19 at 11:22
20

In onCreate with activity or in onCreateView with fragment.

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

}
Cabezas
  • 9,329
  • 7
  • 67
  • 69
16

Ok, call me paranoid but I suggest:

  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

casting without instanceof just seems wrong. And (thanks IntelliJ IDEA for telling me) removeView is part of the ViewManager interface. And one should not cast to a concrete class when a perfectly suitable interface is available.

Martin
  • 11,577
  • 16
  • 80
  • 110
5

Kotlin Solution

Kotlin simplifies parent casting with as?, returning null if left side is null or cast fails.

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

Kotlin Extension Solution

If you want to simplify this even further, you can add this extension.

childView.removeSelf()

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

It will safely do nothing if this View is null, parent view is null, or parent view is not a ViewGroup

NOTE: If you also want safe removal of child views by parent, add this:

fun ViewGroup.removeViewSafe(toRemove: View) {
    if (contains(toRemove)) removeView(toRemove)
}
Gibolt
  • 42,564
  • 15
  • 187
  • 127
3

All you have to do is post() a Runnable that does the addView().

Romain Guy
  • 97,993
  • 18
  • 219
  • 200
  • Didn't work. This is what I tried: scrollView.removeView(scrollChildLayout); scrollView.setVisibility(View.GONE); parentLayout.post(new Runnable() { @Override public void run() { parentLayout.addView(scrollChildLayout); } }); – kasgoku Jun 29 '11 at 21:38
1

I was calling parentView.removeView(childView) and childView was still showing. I eventually realized that a method was somehow being triggered twice and added the childView to the parentView twice.

So, use parentView.getChildCount() to determine how many children the parent has before you add a view and afterwards. If the child is added too many times then the top most child is being removed and the copy childView remains-which looks like removeView is working even when it is.

Also, you shouldn't use View.GONE to remove a view. If it's truly removed then you won't need to hide it, otherwise it's still there and you're just hiding it from yourself :(

Chris Sprague
  • 3,158
  • 33
  • 24
1

In my case , I have BaseFragment and all other fragment inherits from this.

So my solytion was add this lines in OnDestroyView() method

@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();
}
Sirop4ik
  • 4,543
  • 2
  • 54
  • 121
0

You can also do it by checking if View's indexOfView method if indexOfView method returns -1 then we can use.

ViewGroup's detachViewFromParent(v); followed by ViewGroup's removeDetachedView(v, true/false);

0

What I was doing wrong so I got this error is I wasn't instantiating dynamic layout and adding childs to it so got this error

blackHawk
  • 6,047
  • 13
  • 57
  • 100
0

Here is my solution.

Lets say you have two TextViews and put them on a LinearLayout (named ll). You'll put this LinerLayout on another 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> 

When you want to create this structure you need to give parent as inheritance.

If you want use it in an onCreate method this will enough.

Otherwise here is 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());
jwpfox
  • 5,124
  • 11
  • 45
  • 42
ishak O.
  • 168
  • 1
  • 2
  • 14