Call removeView() on the child's parent first

2020-01-23 04:27发布

问题:

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.

回答1:

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



回答2:

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


回答3:

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

}


回答4:

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.



回答5:

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



回答6:

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 :(



回答7:

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


回答8:

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



回答9:

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



回答10:

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