09.15
The Android documentation gives off the impression that the only proper way to chain animations is by calculating their durations and then starting the next animation when the first should’ve been finished. While it works fine for animations sets defined in xml, it does break down when wanting to trigger some action in code right after the animation ended.
When using the conventional way of calculating the end time one could assume that the same is true for triggers that have to happen in code. Say by calling View.postDelayed(..) . This works more or less, but when the delayed runnable is called it isn’t guaranteed that the animation has ended, it might be still running, or worse it ended ages ago and the user just watched a static screen without understanding if he should do something or has the program crashed.
Unless you want to subclass a view that is being animated and override the View.onAnimationEnd() you are pretty much out of options. Under normal circumstances however you don’t want to create another subclass.
There is one way to get this information somewhat reliably. It is to register a callback with Animation.setAnimationListener(…) . When at first it might seem as the fool-proof way there is a situation where it can cause headache.
Say you want to fade out some views (with different durations) and hide them after the animation has ended so they wouldn’t pop up again. And after all of the views have finished their animation close the activity all together.
You could go and write this for every animation for every view:
View viewN = ..;
Animation animN = ...;
animN.setAnimationListener(new AnimationListener() {
// ...
void onAnimationEnd(Animation anim)
{
viewN.setVisibility(View.GONE);
// Check if all the views have been hidden already:
for (View v : allViews)
if (v.getVisibility() !== View.GONE)
return;
// Close the activity:
finish();
}
// ...
});
viewN.startAnimation(animN);
As you can see it will get out of hand pretty fast if using this approach. You end up repeating yourself over and over, instead you’d just want to use something like this:
AnimationListener animListener = new AnimationListener() {
// ...
void onAnimationEnd(Animation anim)
{
View view = getAnimationView(anim);
view.setVisibility(View.GONE);
// Check if all the views have been hidden already:
for (View v : allViews)
if (v.getVisibility() !== View.GONE)
return;
// Close the activity:
finish();
}
// ...
};
// ...
anim1.setAnimationListener(animListener);
anim2.setAnimationListener(animListener);
// ...
And use it with all the animations. This is possible with an hashtable mapping animations to views, so that magic function getAnimactionView(Animation a) will just have to look it up from the hashtable and return it. The catch is that you can’t use the same animation for many views.
Can you show the getAnimationView method?
getAnimationView(…) is just a pseudo function I used to describe the workflow.
When writing the handler you should know how to get the view associated with the animation, so you can just implement that function or replace the line with your own logic of getting that view.
Sorry Mart, I’m still learning Android, if you could elaborate that would be most helpful
How do you find the view (I’m using an ImageView) of the given animation?
Ben, I’m not trying to be an ass or anything, but the best way to learn (in my opinion) is figuring things out for yourself.
Such approach does take up a bit more time, but the end result is that you get a bigger ego boost and you know what things work and what don’t, nor will you forget these things easily.
Besides, my original post already gives a pretty decent idea (hashtable) on how to implement that function.