1ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase/*
2ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase * Copyright (C) 2010 The Android Open Source Project
3ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase *
4ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase * Licensed under the Apache License, Version 2.0 (the "License");
5ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase * you may not use this file except in compliance with the License.
6ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase * You may obtain a copy of the License at
7ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase *
8ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase *      http://www.apache.org/licenses/LICENSE-2.0
9ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase *
10ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase * Unless required by applicable law or agreed to in writing, software
11ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase * distributed under the License is distributed on an "AS IS" BASIS,
12ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase * See the License for the specific language governing permissions and
14ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase * limitations under the License.
15ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase */
16ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
17ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haasepackage com.example.android.apis.animation;
18ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
19ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase// Need the following import to get access to the app resources, since this
20ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase// class is in a sub-package.
21ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.animation.*;
22ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.view.animation.AccelerateInterpolator;
23ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport com.example.android.apis.R;
24ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
25ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport java.util.ArrayList;
26ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
27ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.app.Activity;
28ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.content.Context;
29ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.graphics.Canvas;
30ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.graphics.Paint;
31ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.graphics.RadialGradient;
32ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.graphics.Shader;
33ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.graphics.drawable.ShapeDrawable;
34ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.graphics.drawable.shapes.OvalShape;
35ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.os.Bundle;
36ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.view.View;
37ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.view.animation.BounceInterpolator;
38ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.widget.Button;
39ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haaseimport android.widget.LinearLayout;
40ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
41ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase/**
42d9855a8dbed211de6e1c1cf55e20201349c40432Chet Haase * This application demonstrates the seeking capability of ValueAnimator. The SeekBar in the
43ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase * UI allows you to set the position of the animation. Pressing the Run button will play from
44ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase * the current position of the animation.
45ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase */
46ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haasepublic class MultiPropertyAnimation extends Activity {
47ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
48ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase    private static final int DURATION = 1500;
49ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
50ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase    @Override
51ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase    public void onCreate(Bundle savedInstanceState) {
52ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        super.onCreate(savedInstanceState);
5343828a838397a8b8c5917e1ff43e615098287becChet Haase        setContentView(R.layout.animation_multi_property);
54ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        LinearLayout container = (LinearLayout) findViewById(R.id.container);
55ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        final MyAnimationView animView = new MyAnimationView(this);
56ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        container.addView(animView);
57ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
58ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        Button starter = (Button) findViewById(R.id.startButton);
59ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        starter.setOnClickListener(new View.OnClickListener() {
60ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
61ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            public void onClick(View v) {
62ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                animView.startAnimation();
63ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            }
64ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        });
65ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
66ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase    }
67ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
68d9855a8dbed211de6e1c1cf55e20201349c40432Chet Haase    public class MyAnimationView extends View implements ValueAnimator.AnimatorUpdateListener {
69ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
70ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        private static final float BALL_SIZE = 100f;
71ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
72ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>();
73d9855a8dbed211de6e1c1cf55e20201349c40432Chet Haase        AnimatorSet animation = null;
74d9855a8dbed211de6e1c1cf55e20201349c40432Chet Haase        Animator bounceAnim = null;
75ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        ShapeHolder ball = null;
76ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
77ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        public MyAnimationView(Context context) {
78ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            super(context);
79ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            addBall(50, 0);
80ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            addBall(150, 0);
81ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            addBall(250, 0);
82ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            addBall(350, 0);
83ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        }
84ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
85ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        private void createAnimation() {
86ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            if (bounceAnim == null) {
87ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                ShapeHolder ball;
88ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                ball = balls.get(0);
89e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                ObjectAnimator yBouncer = ObjectAnimator.ofFloat(ball, "y",
90e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                        ball.getY(), getHeight() - BALL_SIZE).setDuration(DURATION);
91ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                yBouncer.setInterpolator(new BounceInterpolator());
92ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                yBouncer.addUpdateListener(this);
93ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
94ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                ball = balls.get(1);
95e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", ball.getY(),
96ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                        getHeight() - BALL_SIZE);
97e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0f);
98e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                ObjectAnimator yAlphaBouncer = ObjectAnimator.ofPropertyValuesHolder(ball,
99e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                        pvhY, pvhAlpha).setDuration(DURATION/2);
100ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                yAlphaBouncer.setInterpolator(new AccelerateInterpolator());
101ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                yAlphaBouncer.setRepeatCount(1);
102d9855a8dbed211de6e1c1cf55e20201349c40432Chet Haase                yAlphaBouncer.setRepeatMode(ValueAnimator.REVERSE);
103ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
104ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
105ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                ball = balls.get(2);
106e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                PropertyValuesHolder pvhW = PropertyValuesHolder.ofFloat("width", ball.getWidth(),
107ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                        ball.getWidth() * 2);
108e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                PropertyValuesHolder pvhH = PropertyValuesHolder.ofFloat("height", ball.getHeight(),
109ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                        ball.getHeight() * 2);
110e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                PropertyValuesHolder pvTX = PropertyValuesHolder.ofFloat("x", ball.getX(),
111e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                        ball.getX() - BALL_SIZE/2f);
1122d3d5377a8e08a4fb83ed394c1a5b84c6a79cd98Chet Haase                PropertyValuesHolder pvTY = PropertyValuesHolder.ofFloat("y", ball.getY(),
113e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                        ball.getY() - BALL_SIZE/2f);
114e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                ObjectAnimator whxyBouncer = ObjectAnimator.ofPropertyValuesHolder(ball, pvhW, pvhH,
115e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                        pvTX, pvTY).setDuration(DURATION/2);
116ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                whxyBouncer.setRepeatCount(1);
117d9855a8dbed211de6e1c1cf55e20201349c40432Chet Haase                whxyBouncer.setRepeatMode(ValueAnimator.REVERSE);
118ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
119ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                ball = balls.get(3);
120e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                pvhY = PropertyValuesHolder.ofFloat("y", ball.getY(), getHeight() - BALL_SIZE);
121ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                float ballX = ball.getX();
1222d3d5377a8e08a4fb83ed394c1a5b84c6a79cd98Chet Haase                Keyframe kf0 = Keyframe.ofFloat(0f, ballX);
1232d3d5377a8e08a4fb83ed394c1a5b84c6a79cd98Chet Haase                Keyframe kf1 = Keyframe.ofFloat(.5f, ballX + 100f);
1242d3d5377a8e08a4fb83ed394c1a5b84c6a79cd98Chet Haase                Keyframe kf2 = Keyframe.ofFloat(1f, ballX + 50f);
125e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                PropertyValuesHolder pvhX = PropertyValuesHolder.ofKeyframe("x", kf0, kf1, kf2);
126e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                ObjectAnimator yxBouncer = ObjectAnimator.ofPropertyValuesHolder(ball, pvhY,
127e358b47be5a1c1a775a376925ea063b51ec3a3f9Chet Haase                        pvhX).setDuration(DURATION/2);
128ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                yxBouncer.setRepeatCount(1);
129d9855a8dbed211de6e1c1cf55e20201349c40432Chet Haase                yxBouncer.setRepeatMode(ValueAnimator.REVERSE);
130ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
131ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
132d9855a8dbed211de6e1c1cf55e20201349c40432Chet Haase                bounceAnim = new AnimatorSet();
1332d3d5377a8e08a4fb83ed394c1a5b84c6a79cd98Chet Haase                ((AnimatorSet)bounceAnim).playTogether(yBouncer, yAlphaBouncer, whxyBouncer,
1342d3d5377a8e08a4fb83ed394c1a5b84c6a79cd98Chet Haase                        yxBouncer);
135ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            }
136ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        }
137ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
138ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        public void startAnimation() {
139ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            createAnimation();
140ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            bounceAnim.start();
141ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        }
142ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
143ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        private ShapeHolder addBall(float x, float y) {
144ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            OvalShape circle = new OvalShape();
145ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            circle.resize(BALL_SIZE, BALL_SIZE);
146ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            ShapeDrawable drawable = new ShapeDrawable(circle);
147ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            ShapeHolder shapeHolder = new ShapeHolder(drawable);
148ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            shapeHolder.setX(x);
149ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            shapeHolder.setY(y);
150ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            int red = (int)(100 + Math.random() * 155);
151ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            int green = (int)(100 + Math.random() * 155);
152ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            int blue = (int)(100 + Math.random() * 155);
153ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            int color = 0xff000000 | red << 16 | green << 8 | blue;
154ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            Paint paint = drawable.getPaint();
155ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            int darkColor = 0xff000000 | red/4 << 16 | green/4 << 8 | blue/4;
156ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            RadialGradient gradient = new RadialGradient(37.5f, 12.5f,
157ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                    50f, color, darkColor, Shader.TileMode.CLAMP);
158ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            paint.setShader(gradient);
159ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            shapeHolder.setPaint(paint);
160ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            balls.add(shapeHolder);
161ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            return shapeHolder;
162ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        }
163ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
164ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        @Override
165ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        protected void onDraw(Canvas canvas) {
166ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            for (ShapeHolder ball : balls) {
167ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                canvas.translate(ball.getX(), ball.getY());
168ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                ball.getShape().draw(canvas);
169ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase                canvas.translate(-ball.getX(), -ball.getY());
170ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            }
171ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        }
172ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
173d9855a8dbed211de6e1c1cf55e20201349c40432Chet Haase        public void onAnimationUpdate(ValueAnimator animation) {
174ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase            invalidate();
175ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase        }
176ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase
177ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase    }
178ce436337daa8e48a743a4e09ec3a56bb3e86006dChet Haase}