Reputation: 5027
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.
Upvotes: 144
Views: 205613
Reputation: 47127
Kotlin simplifies parent casting with as?
, returning null if left side is null or cast fails.
(childView.parent as? ViewGroup)?.removeView(childView)
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)
}
Upvotes: 5
Reputation: 191
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());
Upvotes: 0
Reputation: 5243
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();
}
Upvotes: 1
Reputation: 6307
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
Upvotes: 0
Reputation: 10717
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) {
}
Upvotes: 19
Reputation: 3574
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 :(
Upvotes: 1
Reputation: 11865
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.
Upvotes: 16
Reputation: 1
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);
Upvotes: 0
Reputation: 5027
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
Upvotes: 292
Reputation: 98501
All you have to do is post() a Runnable that does the addView().
Upvotes: 3
Reputation: 6504
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()
Upvotes: 22