1 /* 2 * Copyright 2018 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 androidx.core.animation; 18 19 import android.annotation.SuppressLint; 20 21 import androidx.annotation.FloatRange; 22 23 import org.jspecify.annotations.NonNull; 24 import org.jspecify.annotations.Nullable; 25 26 /** 27 * This class holds a time/value pair for an animation. The Keyframe class is used 28 * by {@link ValueAnimator} to define the values that the animation target will have over the course 29 * of the animation. As the time proceeds from one keyframe to the other, the value of the 30 * target object will animate between the value at the previous keyframe and the value at the 31 * next keyframe. Each keyframe also holds an optional {@link Interpolator} 32 * object, which defines the time interpolation over the intervalue preceding the keyframe. 33 * 34 * <p>The Keyframe class itself is abstract. The type-specific factory methods will return 35 * a subclass of Keyframe specific to the type of value being stored. This is done to improve 36 * performance when dealing with the most common cases (e.g., <code>float</code> and 37 * <code>int</code> values). Other types will fall into a more general Keyframe class that 38 * treats its values as Objects. Unless your animation requires dealing with a custom type 39 * or a data structure that needs to be animated directly (and evaluated using an implementation 40 * of {@link TypeEvaluator}), you should stick to using float and int as animations using those 41 * types have lower runtime overhead than other types.</p> 42 * 43 * @param <T> type of the data value stored in a key frame. 44 */ 45 public abstract class Keyframe<T> implements Cloneable { 46 /** 47 * Flag to indicate whether this keyframe has a valid value. This flag is used when an 48 * animation first starts, to populate placeholder keyframes with real values derived 49 * from the target object. 50 */ 51 boolean mHasValue; 52 53 /** 54 * Flag to indicate whether the value in the keyframe was read from the target object or not. 55 * If so, its value will be recalculated if target changes. 56 */ 57 boolean mValueWasSetOnStart; 58 59 60 /** 61 * The time at which mValue will hold true. 62 */ 63 float mFraction; 64 65 /** 66 * The type of the value in this Keyframe. This type is determined at construction time, 67 * based on the type of the <code>value</code> object passed into the constructor. 68 */ 69 Class<?> mValueType; 70 71 /** 72 * The optional interpolator for the interval preceding this keyframe. A null interpolator 73 * (the default) results in linear interpolation over the interval. 74 */ 75 private Interpolator mInterpolator = null; 76 77 /** 78 * Constructs a Keyframe object with the given time and value. The time defines the 79 * time, as a proportion of an overall animation's duration, at which the value will hold true 80 * for the animation. The value for the animation between keyframes will be calculated as 81 * an interpolation between the values at those keyframes. 82 * 83 * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 84 * of time elapsed of the overall animation duration. 85 * @param value The value that the object will animate to as the animation time approaches 86 * the time in this keyframe, and the the value animated from as the time passes the time in 87 * this keyframe. 88 */ ofInt(@loatRangefrom = 0, to = 1) float fraction, int value)89 public static @NonNull Keyframe<Integer> ofInt(@FloatRange(from = 0, to = 1) float fraction, 90 int value) { 91 return new IntKeyframe(fraction, value); 92 } 93 94 /** 95 * Constructs a Keyframe object with the given time. The value at this time will be derived 96 * from the target object when the animation first starts (note that this implies that keyframes 97 * with no initial value must be used as part of an {@link ObjectAnimator}). 98 * The time defines the 99 * time, as a proportion of an overall animation's duration, at which the value will hold true 100 * for the animation. The value for the animation between keyframes will be calculated as 101 * an interpolation between the values at those keyframes. 102 * 103 * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 104 * of time elapsed of the overall animation duration. 105 */ ofInt(@loatRangefrom = 0, to = 1) float fraction)106 public static @NonNull Keyframe<Integer> ofInt(@FloatRange(from = 0, to = 1) float fraction) { 107 return new IntKeyframe(fraction); 108 } 109 110 /** 111 * Constructs a Keyframe object with the given time and value. The time defines the 112 * time, as a proportion of an overall animation's duration, at which the value will hold true 113 * for the animation. The value for the animation between keyframes will be calculated as 114 * an interpolation between the values at those keyframes. 115 * 116 * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 117 * of time elapsed of the overall animation duration. 118 * @param value The value that the object will animate to as the animation time approaches 119 * the time in this keyframe, and the the value animated from as the time passes the time in 120 * this keyframe. 121 */ ofFloat(@loatRangefrom = 0, to = 1) float fraction, float value)122 public static @NonNull Keyframe<Float> ofFloat(@FloatRange(from = 0, to = 1) float fraction, 123 float value) { 124 return new FloatKeyframe(fraction, value); 125 } 126 127 /** 128 * Constructs a Keyframe object with the given time. The value at this time will be derived 129 * from the target object when the animation first starts (note that this implies that keyframes 130 * with no initial value must be used as part of an {@link ObjectAnimator}). 131 * The time defines the 132 * time, as a proportion of an overall animation's duration, at which the value will hold true 133 * for the animation. The value for the animation between keyframes will be calculated as 134 * an interpolation between the values at those keyframes. 135 * 136 * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 137 * of time elapsed of the overall animation duration. 138 */ ofFloat(@loatRangefrom = 0, to = 1) float fraction)139 public static @NonNull Keyframe<Float> ofFloat(@FloatRange(from = 0, to = 1) float fraction) { 140 return new FloatKeyframe(fraction); 141 } 142 143 /** 144 * Constructs a Keyframe object with the given time and value. The time defines the 145 * time, as a proportion of an overall animation's duration, at which the value will hold true 146 * for the animation. The value for the animation between keyframes will be calculated as 147 * an interpolation between the values at those keyframes. 148 * 149 * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 150 * of time elapsed of the overall animation duration. 151 * @param value The value that the object will animate to as the animation time approaches 152 * the time in this keyframe, and the the value animated from as the time passes the time in 153 * this keyframe. 154 */ ofObject(@loatRangefrom = 0, to = 1) float fraction, @Nullable T value)155 public static <T> @NonNull Keyframe<T> ofObject(@FloatRange(from = 0, to = 1) float fraction, 156 @Nullable T value) { 157 return new ObjectKeyframe<T>(fraction, value); 158 } 159 160 /** 161 * Constructs a Keyframe object with the given time. The value at this time will be derived 162 * from the target object when the animation first starts (note that this implies that keyframes 163 * with no initial value must be used as part of an {@link ObjectAnimator}). 164 * The time defines the 165 * time, as a proportion of an overall animation's duration, at which the value will hold true 166 * for the animation. The value for the animation between keyframes will be calculated as 167 * an interpolation between the values at those keyframes. 168 * 169 * @param fraction The time, expressed as a value between 0 and 1, representing the fraction 170 * of time elapsed of the overall animation duration. 171 */ ofObject(@loatRangefrom = 0, to = 1) float fraction)172 public static <T> @NonNull Keyframe<T> ofObject(@FloatRange(from = 0, to = 1) float fraction) { 173 return new ObjectKeyframe<>(fraction, null); 174 } 175 176 /** 177 * Indicates whether this keyframe has a valid value. This method is called internally when 178 * an {@link ObjectAnimator} first starts; keyframes without values are assigned values at 179 * that time by deriving the value for the property from the target object. 180 * 181 * @return boolean Whether this object has a value assigned. 182 */ hasValue()183 public boolean hasValue() { 184 return mHasValue; 185 } 186 187 /** 188 * If the Keyframe's value was acquired from the target object, this flag should be set so that, 189 * if target changes, value will be reset. 190 * 191 * @return boolean Whether this Keyframe's value was retieved from the target object or not. 192 */ valueWasSetOnStart()193 boolean valueWasSetOnStart() { 194 return mValueWasSetOnStart; 195 } 196 setValueWasSetOnStart(boolean valueWasSetOnStart)197 void setValueWasSetOnStart(boolean valueWasSetOnStart) { 198 mValueWasSetOnStart = valueWasSetOnStart; 199 } 200 201 /** 202 * Gets the value for this Keyframe. 203 * 204 * @return The value for this Keyframe. 205 */ 206 //TODO: Consider removing hasValue() and making keyframe always contain nonNull value, and 207 // using a different signal for when the animation should read the property value as its start 208 // value. getValue()209 public abstract @Nullable T getValue(); 210 211 /** 212 * Sets the value for this Keyframe. 213 * 214 * @param value value for this Keyframe. 215 */ setValue(@ullable T value)216 public abstract void setValue(@Nullable T value); 217 218 /** 219 * Gets the time for this keyframe, as a fraction of the overall animation duration. 220 * 221 * @return The time associated with this keyframe, as a fraction of the overall animation 222 * duration. This should be a value between 0 and 1. 223 */ getFraction()224 public @FloatRange(from = 0, to = 1) float getFraction() { 225 return mFraction; 226 } 227 228 /** 229 * Sets the time for this keyframe, as a fraction of the overall animation duration. 230 * 231 * @param fraction time associated with this keyframe, as a fraction of the overall animation 232 * duration. This should be a value between 0 and 1. 233 */ setFraction(@loatRangefrom = 0, to = 1) float fraction)234 public void setFraction(@FloatRange(from = 0, to = 1) float fraction) { 235 mFraction = fraction; 236 } 237 238 /** 239 * Gets the optional interpolator for this Keyframe. A value of <code>null</code> indicates 240 * that there is no interpolation, which is the same as linear interpolation. 241 * 242 * @return The optional interpolator for this Keyframe. 243 */ getInterpolator()244 public @Nullable Interpolator getInterpolator() { 245 return mInterpolator; 246 } 247 248 /** 249 * Sets the optional interpolator for this Keyframe. A value of <code>null</code> indicates 250 * that there is no interpolation, which is the same as linear interpolation. 251 */ setInterpolator(@ullable Interpolator interpolator)252 public void setInterpolator(@Nullable Interpolator interpolator) { 253 mInterpolator = interpolator; 254 } 255 256 /** 257 * Gets the type of keyframe. This information is used by ValueAnimator to determine the type of 258 * {@link TypeEvaluator} to use when calculating values between keyframes. The type is based 259 * on the type of Keyframe created. 260 * 261 * @return The type of the value stored in the Keyframe. 262 */ getType()263 public @NonNull Class<?> getType() { 264 return mValueType; 265 } 266 267 @SuppressLint("NoClone") /* Platform API */ 268 @Override clone()269 public abstract @NonNull Keyframe<T> clone(); 270 271 /** 272 * This internal subclass is used for all types which are not int or float. 273 */ 274 static class ObjectKeyframe<T> extends Keyframe<T> { 275 276 /** 277 * The value of the animation at the time mFraction. 278 */ 279 T mValue; 280 ObjectKeyframe(float fraction, T value)281 ObjectKeyframe(float fraction, T value) { 282 mFraction = fraction; 283 mValue = value; 284 mHasValue = (value != null); 285 mValueType = mHasValue ? value.getClass() : Object.class; 286 } 287 288 @Override getValue()289 public T getValue() { 290 return mValue; 291 } 292 293 @Override setValue(T value)294 public void setValue(T value) { 295 mValue = value; 296 mHasValue = (value != null); 297 } 298 299 @Override clone()300 public @NonNull ObjectKeyframe<T> clone() { 301 ObjectKeyframe<T> kfClone = new ObjectKeyframe<>(getFraction(), 302 hasValue() ? mValue : null); 303 kfClone.mValueWasSetOnStart = mValueWasSetOnStart; 304 kfClone.setInterpolator(getInterpolator()); 305 return kfClone; 306 } 307 } 308 309 /** 310 * Internal subclass used when the keyframe value is of type int. 311 */ 312 static class IntKeyframe extends Keyframe<Integer> { 313 314 /** 315 * The value of the animation at the time mFraction. 316 */ 317 int mValue; 318 IntKeyframe(float fraction, int value)319 IntKeyframe(float fraction, int value) { 320 mFraction = fraction; 321 mValue = value; 322 mValueType = int.class; 323 mHasValue = true; 324 } 325 IntKeyframe(float fraction)326 IntKeyframe(float fraction) { 327 mFraction = fraction; 328 mValueType = int.class; 329 } 330 getIntValue()331 public int getIntValue() { 332 return mValue; 333 } 334 335 @Override getValue()336 public Integer getValue() { 337 return mValue; 338 } 339 340 @Override setValue(Integer value)341 public void setValue(Integer value) { 342 if (value != null && value.getClass() == Integer.class) { 343 mValue = value.intValue(); 344 mHasValue = true; 345 } 346 } 347 348 @Override clone()349 public @NonNull IntKeyframe clone() { 350 IntKeyframe kfClone = mHasValue ? new IntKeyframe(getFraction(), mValue) : 351 new IntKeyframe(getFraction()); 352 kfClone.setInterpolator(getInterpolator()); 353 kfClone.mValueWasSetOnStart = mValueWasSetOnStart; 354 return kfClone; 355 } 356 } 357 358 /** 359 * Internal subclass used when the keyframe value is of type float. 360 */ 361 static class FloatKeyframe extends Keyframe<Float> { 362 /** 363 * The value of the animation at the time mFraction. 364 */ 365 float mValue; 366 FloatKeyframe(float fraction, float value)367 FloatKeyframe(float fraction, float value) { 368 mFraction = fraction; 369 mValue = value; 370 mValueType = float.class; 371 mHasValue = true; 372 } 373 FloatKeyframe(float fraction)374 FloatKeyframe(float fraction) { 375 mFraction = fraction; 376 mValueType = float.class; 377 } 378 getFloatValue()379 public float getFloatValue() { 380 return mValue; 381 } 382 383 @Override getValue()384 public Float getValue() { 385 return mValue; 386 } 387 388 @Override setValue(Float value)389 public void setValue(Float value) { 390 if (value != null && value.getClass() == Float.class) { 391 mValue = value.floatValue(); 392 mHasValue = true; 393 } 394 } 395 396 @Override clone()397 public @NonNull FloatKeyframe clone() { 398 FloatKeyframe kfClone = mHasValue ? new FloatKeyframe(getFraction(), mValue) : 399 new FloatKeyframe(getFraction()); 400 kfClone.setInterpolator(getInterpolator()); 401 kfClone.mValueWasSetOnStart = mValueWasSetOnStart; 402 return kfClone; 403 } 404 } 405 } 406