Tutorial details

Android: Leaf fall-like animation using property animators | App Code for Sale | Preview

Android: Leaf fall-like animation using property animators | Android Tutorial

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

Overview PAGE TOP

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:

01  private Handler mHandler = new Handler() {
02              @Override
03              public void handleMessage(Message msg) {
04                      super.handleMessage(msg);
05                      int viewId = new Random().nextInt(LEAVES.length);
06                      Drawable d = getResources().getDrawable(LEAVES[viewId]);
07                      LayoutInflater inflate = LayoutInflater.from(FallAnimationActivity.this);
08                      ImageView leafImageView = (ImageView) inflate.inflate(R.layout.ani_image_view,null);
09                      leafImageView.setImageDrawable(d);
10                      mRootLayout.addView(leafImageView);
12                      LayoutParams animationLayout = (LayoutParams) leafImageView.getLayoutParams();
13                      animationLayout.setMargins(0, (int)(-150*mScale), 0, 0);
14                      animationLayout.width = (int) (60*mScale);
15                      animationLayout.height = (int) (60*mScale);
17                      startAnimation(imageView);
18              }
19      };

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:

1   private class AnimTimerTask extends TimerTask {
2               @Override
3               public void run() {
4                       mHandler.sendEmptyMessage(0x001);
5               }
6       }

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

1   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:

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

In our case that’d be:

1   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:

01  public void startAnimation(final ImageView leafImageView) {
03      leafImageView.setPivotX(leafImageView.getWidth()/2);
04      leafImageView.setPivotY(leafImageView.getHeight()/2);
06      long delay = new Random().nextInt(6000);
08      final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
09      animator.setDuration(10000);
10      animator.setInterpolator(new AccelerateInterpolator());
11      animator.setStartDelay(delay);
13      animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
15              int movex = new Random().nextInt(mDisplaySize.right);
16              int angle = 50 + (int)(Math.random() * 101);
18              @Override
19              public void onAnimationUpdate(ValueAnimator animation) {
20                      float value = ((Float) (animation.getAnimatedValue())).floatValue();
22                      leafImageView.setRotation(angle*value);
23                      leafImageView.setTranslationX((movex-40)*value);
24                      leafImageView.setTranslationY((mDisplaySize.bottom + (150*mScale))*value);
25              }
26      });
28      animator.start();
29  }

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 PAGE TOP


0 Comments Leave a comment

Please login in order to leave a comment.

Newest first

to your Chupamobile Account.

The Easiest way to Launch your next App or Game.

Join Chupamobile and get instant access to thousands of ready made App and Game Templates.

Creating an account means you’re okay with Chupamobile’s Terms of Service and Privacy Policy.