Android Core

Android: Leaf fall-like animation using property animators

In the previous tutorial we explained how property animations work in general. Now we’ll go even further and explain how to create a property animation that would create leaf-falling-like effect for an ImageView in which we’ll, apparently put images of leaves. For that purpose we need few images that represent leaves.

We found the ones we use in the example somewhere on the net, hopefully not infringing any designer’s work:

If you don’t have anything better, get this images and use them.

When you imagine a falling leaf represented in digital context you can notice three things:

  • the leaf is falling down
  • the leaf is rotating around its axes at some angle
  • the leaf is making curve movement

These three properties would make the effect of a leaf falling down flown by the wind, taken off the tree. One thing that at this point we won’t implement is the curvic transformation since we plan to create separate tutorial about it, as extension to this one.

So we would need to create translation and rotation, putting some more logics here and there.

In Android sense, as we mentioned earlier the leaves would be ImageView objects. They would be created randomly and added to the root layout right before the animation starts. So we’ll need some timer that would knock-off the animation of a single leaf. Let’s say that we want new leaf every 5 seconds. So we’ll need timer that would send empty message, handled by a Handler object. When the message is handled (received), we get random leaf from a set of leaves (Drawables), create ImageView object and put the drawable as its contents, and add the imageview to the root layout of the activity. Then we call a method which in our case is named ‘startAnimation’ that would accept one ImageView object as parameter which will be animated. We do this in this way so that we leave space in the ‘startAnimation’ method where the ViewAnimator would be create, initialized and started, and also its listener.

Let’s go again step by step. Let’s create the Handler object first:

private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    int viewId = new Random().nextInt(LEAVES.length);
                    Drawable d = getResources().getDrawable(LEAVES[viewId]);
                    LayoutInflater inflate = LayoutInflater.from(FallAnimationActivity.this);
                    ImageView leafImageView = (ImageView) inflate.inflate(R.layout.ani_image_view, null);
                    leafImageView.setImageDrawable(d);
                    mRootLayout.addView(leafImageView);
                                       
                    LayoutParams animationLayout = (LayoutParams) leafImageView.getLayoutParams();
                    animationLayout.setMargins(0, (int)(-150*mScale), 0, 0);
                    animationLayout.width = (int) (60*mScale);
                    animationLayout.height = (int) (60*mScale);
                    
                    startAnimation(imageView);
            }
    };

The leafImageView object is inflated from XML so that we don’t have to create it programmatically, mScale is global field holding the density of the screen (used on few other places in the code, that’s why globally declared). After we add the leafImageView to the root layout we’ll programmatically set its top margin to 150dp in minus only to position it above the visible area of the screen. We create TimerTask like this:

private class AnimTimerTask extends TimerTask {
            @Override
            public void run() {
                    mHandler.sendEmptyMessage(0x001);
            }
    }

and the TimerTask is executed like this, in our case in the onCreate method of the Activity:

new Timer().schedule(new AnimTimerTask(), 0, 5000);

This means, create new imageview every 5 seconds, add it to the root layout and start animation on it.

Now back to the logic of the animation. As we previously mentioned we need a to translate to the bottom and side (x/y) and minor rotate animation. Both pivots (x and y) are the center of the axis, so the center of the leaf imageview.

The delay before the animation starts is again calculated randomly as value between 0 and 6000 (milliseconds). The animator would be ofFloat from 0 to 1.

For now, we set the animation to last for 10 seconds (10000 ms). That might be little fast so you can increase this value as you wish.

What happens in the AnimatorUpdateListener is the following: The final ‘x’ position of the leaf imageview would be calculated as random value from 0 (left of the screen) and display’s width (right of the screen). Any point between this would be the ‘x’ final position. The final ‘y’ position of the leaf imageview would be display’s height/bottom, plus 150dp just to make the view not stop in the visible area. I like to make it fall to some point of display’s height + 10dp which would look just as if the leaf has fallen on the ground. This time, we make the leaf dissapear in the void of the screen.

So now we have an imageview that goes from top to bottom where the x final position is random. But we miss 2 more things (rotation + curve animation) out of which we decided to implement only one more, the rotation. Let’s imagine the wind is not that strong so we need tremble-like effect for the leaf. An angle of 50 to 100 would be enough for this to take effect. One general rule to implement this would be this practice:

Min + (int)(Math.random() * ((Max - Min) + 1))

In our case that’d be:

50 + (int)(Math.random() * 101)

onAnimationUpdate is called till every last frame is done. Rotation and Translation are set here. Lastly we start the animator. Here is the whole method:

public void startAnimation(final ImageView leafImageView) {

    leafImageView.setPivotX(leafImageView.getWidth()/2);
    leafImageView.setPivotY(leafImageView.getHeight()/2);

    long delay = new Random().nextInt(6000);

    final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
    animator.setDuration(10000);
    animator.setInterpolator(new AccelerateInterpolator());
    animator.setStartDelay(delay);

    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    
            int movex = new Random().nextInt(mDisplaySize.right);
            int angle = 50 + (int)(Math.random() * 101);
                    
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                    float value = ((Float) (animation.getAnimatedValue())).floatValue();
                            
                    leafImageView.setRotation(angle*value);
                    leafImageView.setTranslationX((movex-40)*value);
                    leafImageView.setTranslationY((mDisplaySize.bottom + (150*mScale))*value);
            }
    });

    animator.start();
}

When we run this application we’re supposed to see something like this:

We use this animation for our latest project which is in its latest polishing process.

Also, download the sources and see if we’ve missed something or made a mistake explaining the code.

Reference: Android: Leaf fall-like animation using property animators from our JCG partner Aleksandar Balalovski at the 2Dwarfs blog.

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Aditya
Aditya
12 years ago

ur code, is not running in Emulator.
it shows , unfortunately view animation ,example has stopped

Umar
10 years ago

Thanx man… well done 1000+

Gene
Gene
9 years ago

This totally worked for me thanks! A few questions .. that may help others as well : 1) I am trying to control the start position on x-axis so that 3 leaves can fall next to each other, more or less equidistant. Any suggestions how to best do that with this code? .. basically 3 leaves, falling in horizontal-parallel .. A B C 2) How to have a leaf rotate the opposite direction once it has rotated 90 degrees to the right (or left) .. I want to add text, and don’t want it to turn upside down Thanks for… Read more »

Ashish Vohra
Ashish Vohra
8 years ago

I want to make a change in this code, which is, instead of making the leaves fall from a single point I want them to fall from the entire top part of the screen.

How to achieve that effect?

Back to top button