Reputation: 2495
I have a FrameLayout
container that I'm trying to have animate it's changes. I call container.setLayoutTransition(layoutTransition)
on the view, but when I later call container.removeView(v)
the DISAPPEARING
animation isn't executed, the view is simply immediately removed.
Here's my code for the transition:
LayoutTransition layoutTransition = new LayoutTransition();
layoutTransition.setAnimator(LayoutTransition.APPEARING,
ObjectAnimator.ofFloat(null, View.TRANSLATION_Y, toolHeight, 0f));
layoutTransition.setStartDelay(LayoutTransition.APPEARING, 0);
layoutTransition.setDuration(LayoutTransition.APPEARING, 1000);
layoutTransition.setAnimator(LayoutTransition.DISAPPEARING,
ObjectAnimator.ofFloat(null, View.TRANSLATION_Y, 0f, toolHeight));
layoutTransition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
layoutTransition.setDuration(LayoutTransition.DISAPPEARING, 1000);
container.setLayoutTransition(layoutTransition);
And to swap views I do this:
if (container.getChildCount() > 0) {
for (int i = container.getChildCount() - 1; i >= 0; i--) {
container.removeViewAt(i);
}
}
container.addView(newView);
I've slowed down the animations to confirm the situation, and I can clearly see that the APPEARING
transition is executed appropriately, but the DISAPPEARING
transition isn't, the view is simply removed immediately.
I've found that if I remove the view from the LayoutTransition.removeChild()
method it works, but that adds quite a bit of complexity that doesn't seem necessary. Here's what that becomes:
if (container.getChildCount() > 0) {
final View v = container.getChildAt(0);
container.getLayoutTransition().removeChild(container, v);
container.getLayoutTransition().addTransitionListener(new LayoutTransition.TransitionListener() {
@Override
public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
}
@Override
public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
transition.removeTransitionListener(this);
if (transitionType == LayoutTransition.DISAPPEARING) {
container.removeView(view);
}
}
}
}
container.addView(newView);
Think that's bad? That's only for removing a single view at a time, if there is more than one view in the container then I've got to add a transition listener that counts executions to know when to remove itself, and that's just a mess.
The removing itself is interesting, because if I simply put that transition listener on the LayoutTransition
and it doesn't remove itself, then the disappearing transition doesn't run again.
Clearly I'm missing something pertaining to making the remove transition execute. Any help would be appreciated.
EDIT
It's been pointed out to me that adding views cancels the DISAPPEARING
transitions:
public class ViewGroup {
private void addViewInner(...) {
if (mTransition != null) {
// Don't prevent other add transitions from completing, but cancel remove
// transitions to let them complete the process before we add to the container
mTransition.cancel(LayoutTransition.DISAPPEARING);
}
}
}
This doesn't make a lot of sense to me. Wonder what the reasoning is here.
Upvotes: 3
Views: 1862
Reputation: 63293
As you've noticed, LayoutTransition
doesn't really sequence animation types the way some of the newer APIs do. It's designed to handle a single item change at a time. The cleanest code will come from sequencing the add yourself with a delay, rather than chaining listener calls:
if (container.getChildCount() > 0) {
for (int i = container.getChildCount() - 1; i >= 0; i--) {
container.removeViewAt(i);
}
//Start the add once removals are complete
long duration =
container.getLayoutTransition().getDuration(LayoutTransition.DISAPPEARING);
container.postOnAnimationDelayed(new Runnable(){
@Override
public void run() {
container.addView(newView);
}
}, duration);
} else {
container.addView(newView);
}
You might get better choreography out of Scenes for something like this, but that is API 19+
Upvotes: 4