2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com
.actionbarsherlock
.internal
.nineoldandroids
.animation
;
19 import java
.util
.ArrayList
;
20 import java
.util
.Arrays
;
21 import android
.view
.animation
.Interpolator
;
23 import com
.actionbarsherlock
.internal
.nineoldandroids
.animation
.Keyframe
.FloatKeyframe
;
24 import com
.actionbarsherlock
.internal
.nineoldandroids
.animation
.Keyframe
.IntKeyframe
;
25 import com
.actionbarsherlock
.internal
.nineoldandroids
.animation
.Keyframe
.ObjectKeyframe
;
28 * This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
29 * values between those keyframes for a given animation. The class internal to the animation
30 * package because it is an implementation detail of how Keyframes are stored and used.
32 @SuppressWarnings({"rawtypes", "unchecked"})
37 Keyframe mFirstKeyframe
;
38 Keyframe mLastKeyframe
;
39 /*Time*/Interpolator mInterpolator
; // only used in the 2-keyframe case
40 ArrayList
<Keyframe
> mKeyframes
; // only used when there are not 2 keyframes
41 TypeEvaluator mEvaluator
;
44 public KeyframeSet(Keyframe
... keyframes
) {
45 mNumKeyframes
= keyframes
.length
;
46 mKeyframes
= new ArrayList
<Keyframe
>();
47 mKeyframes
.addAll(Arrays
.asList(keyframes
));
48 mFirstKeyframe
= mKeyframes
.get(0);
49 mLastKeyframe
= mKeyframes
.get(mNumKeyframes
- 1);
50 mInterpolator
= mLastKeyframe
.getInterpolator();
53 public static KeyframeSet
ofInt(int... values
) {
54 int numKeyframes
= values
.length
;
55 IntKeyframe keyframes
[] = new IntKeyframe
[Math
.max(numKeyframes
,2)];
56 if (numKeyframes
== 1) {
57 keyframes
[0] = (IntKeyframe
) Keyframe
.ofInt(0f
);
58 keyframes
[1] = (IntKeyframe
) Keyframe
.ofInt(1f
, values
[0]);
60 keyframes
[0] = (IntKeyframe
) Keyframe
.ofInt(0f
, values
[0]);
61 for (int i
= 1; i
< numKeyframes
; ++i
) {
62 keyframes
[i
] = (IntKeyframe
) Keyframe
.ofInt((float) i
/ (numKeyframes
- 1), values
[i
]);
65 return new IntKeyframeSet(keyframes
);
68 public static KeyframeSet
ofFloat(float... values
) {
69 int numKeyframes
= values
.length
;
70 FloatKeyframe keyframes
[] = new FloatKeyframe
[Math
.max(numKeyframes
,2)];
71 if (numKeyframes
== 1) {
72 keyframes
[0] = (FloatKeyframe
) Keyframe
.ofFloat(0f
);
73 keyframes
[1] = (FloatKeyframe
) Keyframe
.ofFloat(1f
, values
[0]);
75 keyframes
[0] = (FloatKeyframe
) Keyframe
.ofFloat(0f
, values
[0]);
76 for (int i
= 1; i
< numKeyframes
; ++i
) {
77 keyframes
[i
] = (FloatKeyframe
) Keyframe
.ofFloat((float) i
/ (numKeyframes
- 1), values
[i
]);
80 return new FloatKeyframeSet(keyframes
);
83 public static KeyframeSet
ofKeyframe(Keyframe
... keyframes
) {
84 // if all keyframes of same primitive type, create the appropriate KeyframeSet
85 int numKeyframes
= keyframes
.length
;
86 boolean hasFloat
= false
;
87 boolean hasInt
= false
;
88 boolean hasOther
= false
;
89 for (int i
= 0; i
< numKeyframes
; ++i
) {
90 if (keyframes
[i
] instanceof FloatKeyframe
) {
92 } else if (keyframes
[i
] instanceof IntKeyframe
) {
98 if (hasFloat
&& !hasInt
&& !hasOther
) {
99 FloatKeyframe floatKeyframes
[] = new FloatKeyframe
[numKeyframes
];
100 for (int i
= 0; i
< numKeyframes
; ++i
) {
101 floatKeyframes
[i
] = (FloatKeyframe
) keyframes
[i
];
103 return new FloatKeyframeSet(floatKeyframes
);
104 } else if (hasInt
&& !hasFloat
&& !hasOther
) {
105 IntKeyframe intKeyframes
[] = new IntKeyframe
[numKeyframes
];
106 for (int i
= 0; i
< numKeyframes
; ++i
) {
107 intKeyframes
[i
] = (IntKeyframe
) keyframes
[i
];
109 return new IntKeyframeSet(intKeyframes
);
111 return new KeyframeSet(keyframes
);
115 public static KeyframeSet
ofObject(Object
... values
) {
116 int numKeyframes
= values
.length
;
117 ObjectKeyframe keyframes
[] = new ObjectKeyframe
[Math
.max(numKeyframes
,2)];
118 if (numKeyframes
== 1) {
119 keyframes
[0] = (ObjectKeyframe
) Keyframe
.ofObject(0f
);
120 keyframes
[1] = (ObjectKeyframe
) Keyframe
.ofObject(1f
, values
[0]);
122 keyframes
[0] = (ObjectKeyframe
) Keyframe
.ofObject(0f
, values
[0]);
123 for (int i
= 1; i
< numKeyframes
; ++i
) {
124 keyframes
[i
] = (ObjectKeyframe
) Keyframe
.ofObject((float) i
/ (numKeyframes
- 1), values
[i
]);
127 return new KeyframeSet(keyframes
);
131 * Sets the TypeEvaluator to be used when calculating animated values. This object
132 * is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet,
133 * both of which assume their own evaluator to speed up calculations with those primitive
136 * @param evaluator The TypeEvaluator to be used to calculate animated values.
138 public void setEvaluator(TypeEvaluator evaluator
) {
139 mEvaluator
= evaluator
;
143 public KeyframeSet
clone() {
144 ArrayList
<Keyframe
> keyframes
= mKeyframes
;
145 int numKeyframes
= mKeyframes
.size();
146 Keyframe
[] newKeyframes
= new Keyframe
[numKeyframes
];
147 for (int i
= 0; i
< numKeyframes
; ++i
) {
148 newKeyframes
[i
] = keyframes
.get(i
).clone();
150 KeyframeSet newSet
= new KeyframeSet(newKeyframes
);
155 * Gets the animated value, given the elapsed fraction of the animation (interpolated by the
156 * animation's interpolator) and the evaluator used to calculate in-between values. This
157 * function maps the input fraction to the appropriate keyframe interval and a fraction
158 * between them and returns the interpolated value. Note that the input fraction may fall
159 * outside the [0-1] bounds, if the animation's interpolator made that happen (e.g., a
160 * spring interpolation that might send the fraction past 1.0). We handle this situation by
161 * just using the two keyframes at the appropriate end when the value is outside those bounds.
163 * @param fraction The elapsed fraction of the animation
164 * @return The animated value.
166 public Object
getValue(float fraction
) {
168 // Special-case optimization for the common case of only two keyframes
169 if (mNumKeyframes
== 2) {
170 if (mInterpolator
!= null
) {
171 fraction
= mInterpolator
.getInterpolation(fraction
);
173 return mEvaluator
.evaluate(fraction
, mFirstKeyframe
.getValue(),
174 mLastKeyframe
.getValue());
176 if (fraction
<= 0f
) {
177 final Keyframe nextKeyframe
= mKeyframes
.get(1);
178 final /*Time*/Interpolator interpolator
= nextKeyframe
.getInterpolator();
179 if (interpolator
!= null
) {
180 fraction
= interpolator
.getInterpolation(fraction
);
182 final float prevFraction
= mFirstKeyframe
.getFraction();
183 float intervalFraction
= (fraction
- prevFraction
) /
184 (nextKeyframe
.getFraction() - prevFraction
);
185 return mEvaluator
.evaluate(intervalFraction
, mFirstKeyframe
.getValue(),
186 nextKeyframe
.getValue());
187 } else if (fraction
>= 1f
) {
188 final Keyframe prevKeyframe
= mKeyframes
.get(mNumKeyframes
- 2);
189 final /*Time*/Interpolator interpolator
= mLastKeyframe
.getInterpolator();
190 if (interpolator
!= null
) {
191 fraction
= interpolator
.getInterpolation(fraction
);
193 final float prevFraction
= prevKeyframe
.getFraction();
194 float intervalFraction
= (fraction
- prevFraction
) /
195 (mLastKeyframe
.getFraction() - prevFraction
);
196 return mEvaluator
.evaluate(intervalFraction
, prevKeyframe
.getValue(),
197 mLastKeyframe
.getValue());
199 Keyframe prevKeyframe
= mFirstKeyframe
;
200 for (int i
= 1; i
< mNumKeyframes
; ++i
) {
201 Keyframe nextKeyframe
= mKeyframes
.get(i
);
202 if (fraction
< nextKeyframe
.getFraction()) {
203 final /*Time*/Interpolator interpolator
= nextKeyframe
.getInterpolator();
204 if (interpolator
!= null
) {
205 fraction
= interpolator
.getInterpolation(fraction
);
207 final float prevFraction
= prevKeyframe
.getFraction();
208 float intervalFraction
= (fraction
- prevFraction
) /
209 (nextKeyframe
.getFraction() - prevFraction
);
210 return mEvaluator
.evaluate(intervalFraction
, prevKeyframe
.getValue(),
211 nextKeyframe
.getValue());
213 prevKeyframe
= nextKeyframe
;
215 // shouldn't reach here
216 return mLastKeyframe
.getValue();
220 public String
toString() {
221 String returnVal
= " ";
222 for (int i
= 0; i
< mNumKeyframes
; ++i
) {
223 returnVal
+= mKeyframes
.get(i
).getValue() + " ";