• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.animation;
18 
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import android.animation.Keyframe.IntKeyframe;
22 import android.animation.Keyframe.FloatKeyframe;
23 import android.animation.Keyframe.ObjectKeyframe;
24 
25 /**
26  * This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
27  * values between those keyframes for a given animation. The class internal to the animation
28  * package because it is an implementation detail of how Keyframes are stored and used.
29  */
30 class KeyframeSet {
31 
32     int mNumKeyframes;
33 
34     Keyframe mFirstKeyframe;
35     Keyframe mLastKeyframe;
36     TimeInterpolator mInterpolator; // only used in the 2-keyframe case
37     ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes
38     TypeEvaluator mEvaluator;
39 
40 
KeyframeSet(Keyframe... keyframes)41     public KeyframeSet(Keyframe... keyframes) {
42         mNumKeyframes = keyframes.length;
43         mKeyframes = new ArrayList<Keyframe>();
44         mKeyframes.addAll(Arrays.asList(keyframes));
45         mFirstKeyframe = mKeyframes.get(0);
46         mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
47         mInterpolator = mLastKeyframe.getInterpolator();
48     }
49 
ofInt(int... values)50     public static KeyframeSet ofInt(int... values) {
51         int numKeyframes = values.length;
52         IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
53         if (numKeyframes == 1) {
54             keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
55             keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
56         } else {
57             keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
58             for (int i = 1; i < numKeyframes; ++i) {
59                 keyframes[i] = (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
60             }
61         }
62         return new IntKeyframeSet(keyframes);
63     }
64 
ofFloat(float... values)65     public static KeyframeSet ofFloat(float... values) {
66         int numKeyframes = values.length;
67         FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
68         if (numKeyframes == 1) {
69             keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
70             keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
71         } else {
72             keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
73             for (int i = 1; i < numKeyframes; ++i) {
74                 keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
75             }
76         }
77         return new FloatKeyframeSet(keyframes);
78     }
79 
ofKeyframe(Keyframe... keyframes)80     public static KeyframeSet ofKeyframe(Keyframe... keyframes) {
81         // if all keyframes of same primitive type, create the appropriate KeyframeSet
82         int numKeyframes = keyframes.length;
83         boolean hasFloat = false;
84         boolean hasInt = false;
85         boolean hasOther = false;
86         for (int i = 0; i < numKeyframes; ++i) {
87             if (keyframes[i] instanceof FloatKeyframe) {
88                 hasFloat = true;
89             } else if (keyframes[i] instanceof IntKeyframe) {
90                 hasInt = true;
91             } else {
92                 hasOther = true;
93             }
94         }
95         if (hasFloat && !hasInt && !hasOther) {
96             FloatKeyframe floatKeyframes[] = new FloatKeyframe[numKeyframes];
97             for (int i = 0; i < numKeyframes; ++i) {
98                 floatKeyframes[i] = (FloatKeyframe) keyframes[i];
99             }
100             return new FloatKeyframeSet(floatKeyframes);
101         } else if (hasInt && !hasFloat && !hasOther) {
102             IntKeyframe intKeyframes[] = new IntKeyframe[numKeyframes];
103             for (int i = 0; i < numKeyframes; ++i) {
104                 intKeyframes[i] = (IntKeyframe) keyframes[i];
105             }
106             return new IntKeyframeSet(intKeyframes);
107         } else {
108             return new KeyframeSet(keyframes);
109         }
110     }
111 
ofObject(Object... values)112     public static KeyframeSet ofObject(Object... values) {
113         int numKeyframes = values.length;
114         ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes,2)];
115         if (numKeyframes == 1) {
116             keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f);
117             keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]);
118         } else {
119             keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]);
120             for (int i = 1; i < numKeyframes; ++i) {
121                 keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]);
122             }
123         }
124         return new KeyframeSet(keyframes);
125     }
126 
127     /**
128      * Sets the TypeEvaluator to be used when calculating animated values. This object
129      * is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet,
130      * both of which assume their own evaluator to speed up calculations with those primitive
131      * types.
132      *
133      * @param evaluator The TypeEvaluator to be used to calculate animated values.
134      */
setEvaluator(TypeEvaluator evaluator)135     public void setEvaluator(TypeEvaluator evaluator) {
136         mEvaluator = evaluator;
137     }
138 
139     @Override
clone()140     public KeyframeSet clone() {
141         ArrayList<Keyframe> keyframes = mKeyframes;
142         int numKeyframes = mKeyframes.size();
143         Keyframe[] newKeyframes = new Keyframe[numKeyframes];
144         for (int i = 0; i < numKeyframes; ++i) {
145             newKeyframes[i] = keyframes.get(i).clone();
146         }
147         KeyframeSet newSet = new KeyframeSet(newKeyframes);
148         return newSet;
149     }
150 
151     /**
152      * Gets the animated value, given the elapsed fraction of the animation (interpolated by the
153      * animation's interpolator) and the evaluator used to calculate in-between values. This
154      * function maps the input fraction to the appropriate keyframe interval and a fraction
155      * between them and returns the interpolated value. Note that the input fraction may fall
156      * outside the [0-1] bounds, if the animation's interpolator made that happen (e.g., a
157      * spring interpolation that might send the fraction past 1.0). We handle this situation by
158      * just using the two keyframes at the appropriate end when the value is outside those bounds.
159      *
160      * @param fraction The elapsed fraction of the animation
161      * @return The animated value.
162      */
getValue(float fraction)163     public Object getValue(float fraction) {
164 
165         // Special-case optimization for the common case of only two keyframes
166         if (mNumKeyframes == 2) {
167             if (mInterpolator != null) {
168                 fraction = mInterpolator.getInterpolation(fraction);
169             }
170             return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),
171                     mLastKeyframe.getValue());
172         }
173         if (fraction <= 0f) {
174             final Keyframe nextKeyframe = mKeyframes.get(1);
175             final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
176             if (interpolator != null) {
177                 fraction = interpolator.getInterpolation(fraction);
178             }
179             final float prevFraction = mFirstKeyframe.getFraction();
180             float intervalFraction = (fraction - prevFraction) /
181                 (nextKeyframe.getFraction() - prevFraction);
182             return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
183                     nextKeyframe.getValue());
184         } else if (fraction >= 1f) {
185             final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
186             final TimeInterpolator interpolator = mLastKeyframe.getInterpolator();
187             if (interpolator != null) {
188                 fraction = interpolator.getInterpolation(fraction);
189             }
190             final float prevFraction = prevKeyframe.getFraction();
191             float intervalFraction = (fraction - prevFraction) /
192                 (mLastKeyframe.getFraction() - prevFraction);
193             return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
194                     mLastKeyframe.getValue());
195         }
196         Keyframe prevKeyframe = mFirstKeyframe;
197         for (int i = 1; i < mNumKeyframes; ++i) {
198             Keyframe nextKeyframe = mKeyframes.get(i);
199             if (fraction < nextKeyframe.getFraction()) {
200                 final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
201                 if (interpolator != null) {
202                     fraction = interpolator.getInterpolation(fraction);
203                 }
204                 final float prevFraction = prevKeyframe.getFraction();
205                 float intervalFraction = (fraction - prevFraction) /
206                     (nextKeyframe.getFraction() - prevFraction);
207                 return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
208                         nextKeyframe.getValue());
209             }
210             prevKeyframe = nextKeyframe;
211         }
212         // shouldn't reach here
213         return mLastKeyframe.getValue();
214     }
215 
216     @Override
toString()217     public String toString() {
218         String returnVal = " ";
219         for (int i = 0; i < mNumKeyframes; ++i) {
220             returnVal += mKeyframes.get(i).getValue() + "  ";
221         }
222         return returnVal;
223     }
224 }
225