• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.example.android.apis.animation;
17 
18 import android.animation.ObjectAnimator;
19 import android.animation.TypeConverter;
20 import android.animation.ValueAnimator;
21 import android.app.Activity;
22 import android.content.Context;
23 import android.graphics.Canvas;
24 import android.graphics.Matrix;
25 import android.graphics.Paint;
26 import android.graphics.Path;
27 import android.graphics.Point;
28 import android.graphics.PointF;
29 import android.graphics.RectF;
30 import android.os.Bundle;
31 import android.util.AttributeSet;
32 import android.util.FloatMath;
33 import android.util.Log;
34 import android.util.Property;
35 import android.view.View;
36 import android.view.animation.Animation;
37 import android.view.animation.LinearInterpolator;
38 import android.widget.FrameLayout;
39 import android.widget.RadioGroup;
40 
41 import com.example.android.apis.R;
42 
43 /** This application demonstrates the use of Path animation. */
44 public class PathAnimations extends Activity implements
45         RadioGroup.OnCheckedChangeListener, View.OnLayoutChangeListener {
46 
47     final static Path sTraversalPath = new Path();
48     final static float TRAVERSE_PATH_SIZE = 7.0f;
49 
50     final static Property<PathAnimations, Point> POINT_PROPERTY
51             = new Property<PathAnimations, Point>(Point.class, "point") {
52         @Override
53         public Point get(PathAnimations object) {
54             View v = object.findViewById(R.id.moved_item);
55             return new Point(Math.round(v.getX()), Math.round(v.getY()));
56         }
57 
58         @Override
59         public void set(PathAnimations object, Point value) {
60             object.setCoordinates(value.x, value.y);
61         }
62     };
63 
64     static {
65         float inverse_sqrt8 = FloatMath.sqrt(0.125f);
66         RectF bounds = new RectF(1, 1, 3, 3);
sTraversalPath.addArc(bounds, 45, 180)67         sTraversalPath.addArc(bounds, 45, 180);
sTraversalPath.addArc(bounds, 225, 180)68         sTraversalPath.addArc(bounds, 225, 180);
69 
70         bounds.set(1.5f + inverse_sqrt8, 1.5f + inverse_sqrt8, 2.5f + inverse_sqrt8,
71                 2.5f + inverse_sqrt8);
sTraversalPath.addArc(bounds, 45, 180)72         sTraversalPath.addArc(bounds, 45, 180);
sTraversalPath.addArc(bounds, 225, 180)73         sTraversalPath.addArc(bounds, 225, 180);
74 
75         bounds.set(4, 1, 6, 3);
sTraversalPath.addArc(bounds, 135, -180)76         sTraversalPath.addArc(bounds, 135, -180);
sTraversalPath.addArc(bounds, -45, -180)77         sTraversalPath.addArc(bounds, -45, -180);
78 
79         bounds.set(4.5f - inverse_sqrt8, 1.5f + inverse_sqrt8, 5.5f - inverse_sqrt8, 2.5f + inverse_sqrt8);
sTraversalPath.addArc(bounds, 135, -180)80         sTraversalPath.addArc(bounds, 135, -180);
sTraversalPath.addArc(bounds, -45, -180)81         sTraversalPath.addArc(bounds, -45, -180);
82 
83         sTraversalPath.addCircle(3.5f, 3.5f, 0.5f, Path.Direction.CCW);
84 
sTraversalPath.addArc(new RectF(1, 2, 6, 6), 0, 180)85         sTraversalPath.addArc(new RectF(1, 2, 6, 6), 0, 180);
86     }
87 
88     private CanvasView mCanvasView;
89 
90     private ObjectAnimator mAnimator;
91 
92     /** Called when the activity is first created. */
93     @Override
onCreate(Bundle savedInstanceState)94     public void onCreate(Bundle savedInstanceState) {
95         super.onCreate(savedInstanceState);
96         setContentView(R.layout.path_animations);
97         mCanvasView = (CanvasView) findViewById(R.id.canvas);
98         mCanvasView.addOnLayoutChangeListener(this);
99         ((RadioGroup) findViewById(R.id.path_animation_type)).setOnCheckedChangeListener(this);
100     }
101 
setCoordinates(int x, int y)102     public void setCoordinates(int x, int y) {
103         changeCoordinates((float) x, (float) y);
104     }
105 
changeCoordinates(float x, float y)106     public void changeCoordinates(float x, float y) {
107         View v = findViewById(R.id.moved_item);
108         v.setX(x);
109         v.setY(y);
110     }
111 
setPoint(PointF point)112     public void setPoint(PointF point) {
113         changeCoordinates(point.x, point.y);
114     }
115 
116     @Override
onCheckedChanged(RadioGroup group, int checkedId)117     public void onCheckedChanged(RadioGroup group, int checkedId) {
118         startAnimator(checkedId);
119     }
120 
121     @Override
onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)122     public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
123             int oldTop, int oldRight, int oldBottom) {
124         int checkedId = ((RadioGroup)findViewById(R.id.path_animation_type)).getCheckedRadioButtonId();
125         if (checkedId != RadioGroup.NO_ID) {
126             startAnimator(checkedId);
127         }
128     }
129 
startAnimator(int checkedId)130     private void startAnimator(int checkedId) {
131         if (mAnimator != null) {
132             mAnimator.cancel();
133             mAnimator = null;
134         }
135 
136         View view = findViewById(R.id.moved_item);
137         Path path = mCanvasView.getPath();
138         if (path.isEmpty()) {
139             return;
140         }
141 
142         switch (checkedId) {
143             case R.id.named_components:
144                 // Use the named "x" and "y" properties for individual (x, y)
145                 // coordinates of the Path and set them on the view object.
146                 // The setX(float) and setY(float) methods are called on view.
147                 // An int version of this method also exists for animating
148                 // int Properties.
149                 mAnimator = ObjectAnimator.ofFloat(view, "x", "y", path);
150                 break;
151             case R.id.property_components:
152                 // Use two Properties for individual (x, y) coordinates of the Path
153                 // and set them on the view object.
154                 // An int version of this method also exists for animating
155                 // int Properties.
156                 mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
157                 break;
158             case R.id.multi_int:
159                 // Use a multi-int setter to animate along a Path. The method
160                 // setCoordinates(int x, int y) is called on this during the animation.
161                 // Either "setCoordinates" or "coordinates" are acceptable parameters
162                 // because the "set" can be implied.
163                 mAnimator = ObjectAnimator.ofMultiInt(this, "setCoordinates", path);
164                 break;
165             case R.id.multi_float:
166                 // Use a multi-float setter to animate along a Path. The method
167                 // changeCoordinates(float x, float y) is called on this during the animation.
168                 mAnimator = ObjectAnimator.ofMultiFloat(this, "changeCoordinates", path);
169                 break;
170             case R.id.named_setter:
171                 // Use the named "point" property to animate along the Path.
172                 // There must be a method setPoint(PointF) on the animated object.
173                 // Because setPoint takes a PointF parameter, no TypeConverter is necessary.
174                 // In this case, the animated object is PathAnimations.
175                 mAnimator = ObjectAnimator.ofObject(this, "point", null, path);
176                 break;
177             case R.id.property_setter:
178                 // Use the POINT_PROPERTY property to animate along the Path.
179                 // POINT_PROPERTY takes a Point, not a PointF, so the TypeConverter
180                 // PointFToPointConverter is necessary.
181                 mAnimator = ObjectAnimator.ofObject(this, POINT_PROPERTY,
182                         new PointFToPointConverter(), path);
183                 break;
184         }
185 
186         mAnimator.setDuration(10000);
187         mAnimator.setRepeatMode(Animation.RESTART);
188         mAnimator.setRepeatCount(ValueAnimator.INFINITE);
189         mAnimator.setInterpolator(new LinearInterpolator());
190         mAnimator.start();
191     }
192 
193     public static class CanvasView extends FrameLayout {
194 
195         Path mPath = new Path();
196 
197         Paint mPathPaint = new Paint();
198 
CanvasView(Context context)199         public CanvasView(Context context) {
200             super(context);
201             init();
202         }
203 
CanvasView(Context context, AttributeSet attrs)204         public CanvasView(Context context, AttributeSet attrs) {
205             super(context, attrs);
206             init();
207         }
208 
CanvasView(Context context, AttributeSet attrs, int defStyle)209         public CanvasView(Context context, AttributeSet attrs, int defStyle) {
210             super(context, attrs, defStyle);
211             init();
212         }
213 
init()214         private void init() {
215             setWillNotDraw(false);
216             mPathPaint.setColor(0xFFFF0000);
217             mPathPaint.setStrokeWidth(2.0f);
218             mPathPaint.setStyle(Paint.Style.STROKE);
219         }
220 
221         @Override
onLayout(boolean changed, int left, int top, int right, int bottom)222         protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
223             super.onLayout(changed, left, top, right, bottom);
224             if (changed) {
225                 Matrix scale = new Matrix();
226                 float scaleWidth = (right-left)/TRAVERSE_PATH_SIZE;
227                 float scaleHeight= (bottom-top)/TRAVERSE_PATH_SIZE;
228                 scale.setScale(scaleWidth, scaleHeight);
229                 sTraversalPath.transform(scale, mPath);
230             }
231         }
232 
getPath()233         public Path getPath() {
234             return mPath;
235         }
236 
237         @Override
draw(Canvas canvas)238         public void draw(Canvas canvas) {
239             canvas.drawPath(mPath, mPathPaint);
240             super.draw(canvas);
241         }
242     }
243 
244     private static class PointFToPointConverter extends TypeConverter<PointF, Point> {
245         Point mPoint = new Point();
246 
PointFToPointConverter()247         public PointFToPointConverter() {
248             super(PointF.class, Point.class);
249         }
250 
251         @Override
convert(PointF value)252         public Point convert(PointF value) {
253             mPoint.set(Math.round(value.x), Math.round(value.y));
254             return mPoint;
255         }
256     }
257 }
258