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.

Related Whitepaper:

Rapid Android Development: Build Rich, Sensor-Based Applications with Processing

Create mobile apps for Android phones and tablets faster and more easily than you ever imagined

Use 'Processing', the free, award-winning, graphics-savvy language and development environment, to work with the touchscreens, hardware sensors, cameras, network transceivers, and other devices and software in the latest Android phones and tablets.

Get it Now!  

2 Responses to "Android: Leaf fall-like animation using property animators"

  1. Aditya says:

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

  2. Umar says:

    Thanx man… well done 1000+

Leave a Reply


two − = 1



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books