I am trying to use a ConstraintLayout
in conjunction with views that slide up and down with animation.
These views are organized vertically, with a RecyclerView
at the top and two other views stacked under it:
<constraint layout container>
[ ]
[ recycler view ]
[ ]
[48dp height 1st view]
[48dp height 2nd view]
</constraint layout container>
The animation is very simple: When a button is tapped the 1st view moves from the bottom of the container to the position you can see above, when tapped again it moves down and stays overlapped on the 2nd view. When this happens the RecyclerView
at the top changes height since it is constrained to that 1st view, otherwise it would leave an empty space.
So far so good and the animation is working well, but the problem arises when the user taps the button too fast, leading to the following error:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
After investigating what was going on I discovered that this problem is a consequence of the TransitionManager
that I am using to animate the changes. What I discovered was interesting, when the button was tapped to move the 1st view up (or down, just imagine the opposite steps) the manager was doing the following:
- Fade out the first/last view from the
RecyclerView
(depends on whether or not you have a reversed layout or stack from end enabled) - Remove that view from the
RecyclerView
- Decrease the height of the
RecyclerView
- Move the 1st view up
Even though I specified in all the places I could imagine that the RecyclerView
should not animate item changes, the TransitionManager
was overriding it and that meant there is a window when the same view that is being about to be removed from the RecyclerView
can be added again to the same parent, and that window is when the view is fading out by the manager.
Since the fade animation is not that fast, a user can very easily tap the button twice during that time, causing the manager to re-add the fading view, which is already in the RecyclerView
and thus crashing the app while throwing the above error.
Since this is an issue caused inside the RecyclerView
I would be perfectly fine with no animations inside it and for that reason I would like to know how can I specify in the TransitionManager.beginDelayedTransition
to only animate the direct child views of the ConstraintLayout
, this way it will not animate the views inside the RecyclerView
.
The related documentation does not shine anything over this, so I present here this question; How can I restrict the transition to direct child views?
In case it might be helpful I include here the snippet of the transition manager
final ConstraintSet constraintSet;
final ConstraintLayout constraintLayout;
constraintSet = new ConstraintSet();
constraintLayout = (ConstraintLayout) viewParent;
TransitionManager.beginDelayedTransition(constraintLayout);
constraintSet.clone(constraintLayout);
constraintSet.connect(startId, startSide, endId, endSide, margin);
constraintSet.applyTo(constraintLayout);
TransitionManager.beginDelayedTransition
and pass aTransition
that excludes some of your views – SnashallTransitionSet
has a method that allows child views to be ignored, thanks. Can you post the answer so that I can accept it? – GroomeTransition
has that methods:Transition#excludeTarget
/Transition#excludeChildren
/Transition#removeTarget
– Snashall