// BouncingBallsAnimationActivity.java by Kari Laitinen // http://www.naturalprogramming.com/ // 2012-09-13 File created. // 2012-09-14 Last modification. /* This is a modified verion of BouncingBalls.java from the standard Android sample applications. More information related to animation in Android: http://developer.android.com/guide/topics/graphics/index.html */ package bouncing.balls.animation; import android.graphics.drawable.ColorDrawable; import android.animation.*; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RadialGradient; import android.graphics.Shader; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.LinearLayout; import java.util.ArrayList; public class BouncingBallsAnimationActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView( new MyAnimationView( this ) ) ; //setContentView(R.layout.bouncing_balls); //LinearLayout container = (LinearLayout) findViewById(R.id.container); //container.addView(new MyAnimationView(this)); } public class MyAnimationView extends View { private static final int RED = 0xffFF8080; private static final int BLUE = 0xff8080FF; private static final int CYAN = 0xff80ffff; private static final int GREEN = 0xff80ff80; public final ArrayList balls = new ArrayList(); AnimatorSet animation = null; public MyAnimationView( Context context ) { super(context); // The following animator will automatically generate calls to the // setBackgroundColor() method of this object. // Note that setting the background color will automatically invalidate the // view, so that the animated color, and the bouncing balls, get redisplayed on // every frame of the animation. ValueAnimator background_color_animator = ObjectAnimator.ofInt( this, "backgroundColor", RED, BLUE ) ; background_color_animator.setDuration( 3000 ) ; background_color_animator.setEvaluator( new ArgbEvaluator() ) ; background_color_animator.setRepeatCount( ValueAnimator.INFINITE ) ; background_color_animator.setRepeatMode( ValueAnimator.REVERSE ) ; background_color_animator.start() ; } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() != MotionEvent.ACTION_DOWN && event.getAction() != MotionEvent.ACTION_MOVE) { return false; } ShapeHolder newBall = addBall(event.getX(), event.getY()); // Bouncing animation with squash and stretch float startY = newBall.getY(); float endY = getHeight() - 50f; float h = (float)getHeight(); float eventY = event.getY(); int duration = (int)(500 * ((h - eventY)/h)); ValueAnimator bounceAnim = ObjectAnimator.ofFloat(newBall, "y", startY, endY); bounceAnim.setDuration(duration); bounceAnim.setInterpolator(new AccelerateInterpolator()); ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall, "x", newBall.getX(), newBall.getX() - 25f); squashAnim1.setDuration(duration/4); squashAnim1.setRepeatCount(1); squashAnim1.setRepeatMode(ValueAnimator.REVERSE); squashAnim1.setInterpolator(new DecelerateInterpolator()); ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall, "width", newBall.getWidth(), newBall.getWidth() + 50); squashAnim2.setDuration(duration/4); squashAnim2.setRepeatCount(1); squashAnim2.setRepeatMode(ValueAnimator.REVERSE); squashAnim2.setInterpolator(new DecelerateInterpolator()); ValueAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall, "y", endY, endY + 25f); stretchAnim1.setDuration(duration/4); stretchAnim1.setRepeatCount(1); stretchAnim1.setInterpolator(new DecelerateInterpolator()); stretchAnim1.setRepeatMode(ValueAnimator.REVERSE); ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall, "height", newBall.getHeight(), newBall.getHeight() - 25); stretchAnim2.setDuration(duration/4); stretchAnim2.setRepeatCount(1); stretchAnim2.setInterpolator(new DecelerateInterpolator()); stretchAnim2.setRepeatMode(ValueAnimator.REVERSE); ValueAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall, "y", endY, startY); bounceBackAnim.setDuration(duration); bounceBackAnim.setInterpolator(new DecelerateInterpolator()); // Sequence the down/squash&stretch/up animations AnimatorSet bouncer = new AnimatorSet() ; bouncer.play(bounceAnim).before(squashAnim1); bouncer.play(squashAnim1).with(squashAnim2); bouncer.play(squashAnim1).with(stretchAnim1); bouncer.play(squashAnim1).with(stretchAnim2); bouncer.play(bounceBackAnim).after(stretchAnim2); // Fading animation - remove the ball when the animation is done ValueAnimator final_fading_animator = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f); final_fading_animator.setDuration( 250 ) ; final_fading_animator.addListener( new AnimatorListenerAdapter() { @Override public void onAnimationEnd( Animator animation ) { balls.remove( ((ObjectAnimator)animation).getTarget() ) ; } }); // Sequence the two animations to play one after the other AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(bouncer).before( final_fading_animator ) ; // Start the animation animatorSet.start(); return true; } private ShapeHolder addBall(float x, float y) { OvalShape circle = new OvalShape(); circle.resize(50f, 50f); ShapeDrawable drawable = new ShapeDrawable( circle ) ; ShapeHolder shapeHolder = new ShapeHolder(drawable); shapeHolder.setX(x - 25f); shapeHolder.setY(y - 25f); int red = (int)(Math.random() * 255); int green = (int)(Math.random() * 255); int blue = (int)(Math.random() * 255); int color = 0xff000000 | red << 16 | green << 8 | blue; Paint paint = drawable.getPaint(); //new Paint(Paint.ANTI_ALIAS_FLAG); int darkColor = 0xff000000 | red/4 << 16 | green/4 << 8 | blue/4; RadialGradient gradient = new RadialGradient(37.5f, 12.5f, 50f, color, darkColor, Shader.TileMode.CLAMP); paint.setShader(gradient); shapeHolder.setPaint(paint); balls.add(shapeHolder); return shapeHolder; } @Override protected void onDraw( Canvas canvas ) { for (int i = 0; i < balls.size(); ++i) { ShapeHolder shapeHolder = balls.get(i); canvas.save(); canvas.translate(shapeHolder.getX(), shapeHolder.getY()); shapeHolder.getShape().draw(canvas); canvas.restore(); } } } }