1 /*
2  * Copyright (C) 2006 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 
17 package android.view.animation;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.content.res.TypedArray;
22 import android.util.AttributeSet;
23 import android.util.TypedValue;
24 
25 /**
26  * An animation that controls the scale of an object. You can specify the point
27  * to use for the center of scaling.
28  *
29  */
30 public class ScaleAnimation extends Animation {
31     private final Resources mResources;
32 
33     private float mFromX;
34     private float mToX;
35     private float mFromY;
36     private float mToY;
37 
38     private int mFromXType = TypedValue.TYPE_NULL;
39     private int mToXType = TypedValue.TYPE_NULL;
40     private int mFromYType = TypedValue.TYPE_NULL;
41     private int mToYType = TypedValue.TYPE_NULL;
42 
43     private int mFromXData = 0;
44     private int mToXData = 0;
45     private int mFromYData = 0;
46     private int mToYData = 0;
47 
48     private int mPivotXType = ABSOLUTE;
49     private int mPivotYType = ABSOLUTE;
50     private float mPivotXValue = 0.0f;
51     private float mPivotYValue = 0.0f;
52 
53     private float mPivotX;
54     private float mPivotY;
55 
56     /**
57      * Constructor used when a ScaleAnimation is loaded from a resource.
58      *
59      * @param context Application context to use
60      * @param attrs Attribute set from which to read values
61      */
ScaleAnimation(Context context, AttributeSet attrs)62     public ScaleAnimation(Context context, AttributeSet attrs) {
63         super(context, attrs);
64 
65         mResources = context.getResources();
66 
67         TypedArray a = context.obtainStyledAttributes(attrs,
68                 com.android.internal.R.styleable.ScaleAnimation);
69 
70         TypedValue tv = a.peekValue(
71                 com.android.internal.R.styleable.ScaleAnimation_fromXScale);
72         mFromX = 0.0f;
73         if (tv != null) {
74             if (tv.type == TypedValue.TYPE_FLOAT) {
75                 // This is a scaling factor.
76                 mFromX = tv.getFloat();
77             } else {
78                 mFromXType = tv.type;
79                 mFromXData = tv.data;
80             }
81         }
82         tv = a.peekValue(
83                 com.android.internal.R.styleable.ScaleAnimation_toXScale);
84         mToX = 0.0f;
85         if (tv != null) {
86             if (tv.type == TypedValue.TYPE_FLOAT) {
87                 // This is a scaling factor.
88                 mToX = tv.getFloat();
89             } else {
90                 mToXType = tv.type;
91                 mToXData = tv.data;
92             }
93         }
94 
95         tv = a.peekValue(
96                 com.android.internal.R.styleable.ScaleAnimation_fromYScale);
97         mFromY = 0.0f;
98         if (tv != null) {
99             if (tv.type == TypedValue.TYPE_FLOAT) {
100                 // This is a scaling factor.
101                 mFromY = tv.getFloat();
102             } else {
103                 mFromYType = tv.type;
104                 mFromYData = tv.data;
105             }
106         }
107         tv = a.peekValue(
108                 com.android.internal.R.styleable.ScaleAnimation_toYScale);
109         mToY = 0.0f;
110         if (tv != null) {
111             if (tv.type == TypedValue.TYPE_FLOAT) {
112                 // This is a scaling factor.
113                 mToY = tv.getFloat();
114             } else {
115                 mToYType = tv.type;
116                 mToYData = tv.data;
117             }
118         }
119 
120         Description d = Description.parseValue(a.peekValue(
121                 com.android.internal.R.styleable.ScaleAnimation_pivotX));
122         mPivotXType = d.type;
123         mPivotXValue = d.value;
124 
125         d = Description.parseValue(a.peekValue(
126             com.android.internal.R.styleable.ScaleAnimation_pivotY));
127         mPivotYType = d.type;
128         mPivotYValue = d.value;
129 
130         a.recycle();
131 
132         initializePivotPoint();
133     }
134 
135     /**
136      * Constructor to use when building a ScaleAnimation from code
137      *
138      * @param fromX Horizontal scaling factor to apply at the start of the
139      *        animation
140      * @param toX Horizontal scaling factor to apply at the end of the animation
141      * @param fromY Vertical scaling factor to apply at the start of the
142      *        animation
143      * @param toY Vertical scaling factor to apply at the end of the animation
144      */
ScaleAnimation(float fromX, float toX, float fromY, float toY)145     public ScaleAnimation(float fromX, float toX, float fromY, float toY) {
146         mResources = null;
147         mFromX = fromX;
148         mToX = toX;
149         mFromY = fromY;
150         mToY = toY;
151         mPivotX = 0;
152         mPivotY = 0;
153     }
154 
155     /**
156      * Constructor to use when building a ScaleAnimation from code
157      *
158      * @param fromX Horizontal scaling factor to apply at the start of the
159      *        animation
160      * @param toX Horizontal scaling factor to apply at the end of the animation
161      * @param fromY Vertical scaling factor to apply at the start of the
162      *        animation
163      * @param toY Vertical scaling factor to apply at the end of the animation
164      * @param pivotX The X coordinate of the point about which the object is
165      *        being scaled, specified as an absolute number where 0 is the left
166      *        edge. (This point remains fixed while the object changes size.)
167      * @param pivotY The Y coordinate of the point about which the object is
168      *        being scaled, specified as an absolute number where 0 is the top
169      *        edge. (This point remains fixed while the object changes size.)
170      */
ScaleAnimation(float fromX, float toX, float fromY, float toY, float pivotX, float pivotY)171     public ScaleAnimation(float fromX, float toX, float fromY, float toY,
172             float pivotX, float pivotY) {
173         mResources = null;
174         mFromX = fromX;
175         mToX = toX;
176         mFromY = fromY;
177         mToY = toY;
178 
179         mPivotXType = ABSOLUTE;
180         mPivotYType = ABSOLUTE;
181         mPivotXValue = pivotX;
182         mPivotYValue = pivotY;
183         initializePivotPoint();
184     }
185 
186     /**
187      * Constructor to use when building a ScaleAnimation from code
188      *
189      * @param fromX Horizontal scaling factor to apply at the start of the
190      *        animation
191      * @param toX Horizontal scaling factor to apply at the end of the animation
192      * @param fromY Vertical scaling factor to apply at the start of the
193      *        animation
194      * @param toY Vertical scaling factor to apply at the end of the animation
195      * @param pivotXType Specifies how pivotXValue should be interpreted. One of
196      *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
197      *        Animation.RELATIVE_TO_PARENT.
198      * @param pivotXValue The X coordinate of the point about which the object
199      *        is being scaled, specified as an absolute number where 0 is the
200      *        left edge. (This point remains fixed while the object changes
201      *        size.) This value can either be an absolute number if pivotXType
202      *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
203      * @param pivotYType Specifies how pivotYValue should be interpreted. One of
204      *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
205      *        Animation.RELATIVE_TO_PARENT.
206      * @param pivotYValue The Y coordinate of the point about which the object
207      *        is being scaled, specified as an absolute number where 0 is the
208      *        top edge. (This point remains fixed while the object changes
209      *        size.) This value can either be an absolute number if pivotYType
210      *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
211      */
ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)212     public ScaleAnimation(float fromX, float toX, float fromY, float toY,
213             int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
214         mResources = null;
215         mFromX = fromX;
216         mToX = toX;
217         mFromY = fromY;
218         mToY = toY;
219 
220         mPivotXValue = pivotXValue;
221         mPivotXType = pivotXType;
222         mPivotYValue = pivotYValue;
223         mPivotYType = pivotYType;
224         initializePivotPoint();
225     }
226 
227     /**
228      * Called at the end of constructor methods to initialize, if possible, values for
229      * the pivot point. This is only possible for ABSOLUTE pivot values.
230      */
initializePivotPoint()231     private void initializePivotPoint() {
232         if (mPivotXType == ABSOLUTE) {
233             mPivotX = mPivotXValue;
234         }
235         if (mPivotYType == ABSOLUTE) {
236             mPivotY = mPivotYValue;
237         }
238     }
239 
240     @Override
applyTransformation(float interpolatedTime, Transformation t)241     protected void applyTransformation(float interpolatedTime, Transformation t) {
242         float sx = 1.0f;
243         float sy = 1.0f;
244         float scale = getScaleFactor();
245 
246         if (mFromX != 1.0f || mToX != 1.0f) {
247             sx = mFromX + ((mToX - mFromX) * interpolatedTime);
248         }
249         if (mFromY != 1.0f || mToY != 1.0f) {
250             sy = mFromY + ((mToY - mFromY) * interpolatedTime);
251         }
252 
253         if (mPivotX == 0 && mPivotY == 0) {
254             t.getMatrix().setScale(sx, sy);
255         } else {
256             t.getMatrix().setScale(sx, sy, scale * mPivotX, scale * mPivotY);
257         }
258     }
259 
resolveScale(float scale, int type, int data, int size, int psize)260     float resolveScale(float scale, int type, int data, int size, int psize) {
261         float targetSize;
262         if (type == TypedValue.TYPE_FRACTION) {
263             targetSize = TypedValue.complexToFraction(data, size, psize);
264         } else if (type == TypedValue.TYPE_DIMENSION) {
265             targetSize = TypedValue.complexToDimension(data, mResources.getDisplayMetrics());
266         } else {
267             return scale;
268         }
269 
270         if (size == 0) {
271             return 1;
272         }
273 
274         return targetSize/(float)size;
275     }
276 
277     @Override
initialize(int width, int height, int parentWidth, int parentHeight)278     public void initialize(int width, int height, int parentWidth, int parentHeight) {
279         super.initialize(width, height, parentWidth, parentHeight);
280 
281         mFromX = resolveScale(mFromX, mFromXType, mFromXData, width, parentWidth);
282         mToX = resolveScale(mToX, mToXType, mToXData, width, parentWidth);
283         mFromY = resolveScale(mFromY, mFromYType, mFromYData, height, parentHeight);
284         mToY = resolveScale(mToY, mToYType, mToYData, height, parentHeight);
285 
286         mPivotX = resolveSize(mPivotXType, mPivotXValue, width, parentWidth);
287         mPivotY = resolveSize(mPivotYType, mPivotYValue, height, parentHeight);
288     }
289 }
290