1 package com.airbnb.lottie.value; 2 3 import android.graphics.PointF; 4 import android.view.animation.Interpolator; 5 6 import androidx.annotation.FloatRange; 7 import androidx.annotation.Nullable; 8 9 import com.airbnb.lottie.LottieComposition; 10 11 public class Keyframe<T> { 12 private static final float UNSET_FLOAT = -3987645.78543923f; 13 private static final int UNSET_INT = 784923401; 14 15 @Nullable private final LottieComposition composition; 16 @Nullable public final T startValue; 17 @Nullable public T endValue; 18 @Nullable public final Interpolator interpolator; 19 @Nullable public final Interpolator xInterpolator; 20 @Nullable public final Interpolator yInterpolator; 21 public final float startFrame; 22 @Nullable public Float endFrame; 23 24 private float startValueFloat = UNSET_FLOAT; 25 private float endValueFloat = UNSET_FLOAT; 26 27 private int startValueInt = UNSET_INT; 28 private int endValueInt = UNSET_INT; 29 30 private float startProgress = Float.MIN_VALUE; 31 private float endProgress = Float.MIN_VALUE; 32 33 // Used by PathKeyframe but it has to be parsed by KeyFrame because we use a JsonReader to 34 // deserialzie the data so we have to parse everything in order 35 public PointF pathCp1 = null; 36 public PointF pathCp2 = null; 37 38 Keyframe(@uppressWarnings"NullableProblems") LottieComposition composition, @Nullable T startValue, @Nullable T endValue, @Nullable Interpolator interpolator, float startFrame, @Nullable Float endFrame)39 public Keyframe(@SuppressWarnings("NullableProblems") LottieComposition composition, 40 @Nullable T startValue, @Nullable T endValue, 41 @Nullable Interpolator interpolator, float startFrame, @Nullable Float endFrame) { 42 this.composition = composition; 43 this.startValue = startValue; 44 this.endValue = endValue; 45 this.interpolator = interpolator; 46 xInterpolator = null; 47 yInterpolator = null; 48 this.startFrame = startFrame; 49 this.endFrame = endFrame; 50 } 51 Keyframe(@uppressWarnings"NullableProblems") LottieComposition composition, @Nullable T startValue, @Nullable T endValue, @Nullable Interpolator xInterpolator, @Nullable Interpolator yInterpolator, float startFrame, @Nullable Float endFrame)52 public Keyframe(@SuppressWarnings("NullableProblems") LottieComposition composition, 53 @Nullable T startValue, @Nullable T endValue, 54 @Nullable Interpolator xInterpolator, @Nullable Interpolator yInterpolator, float startFrame, @Nullable Float endFrame) { 55 this.composition = composition; 56 this.startValue = startValue; 57 this.endValue = endValue; 58 interpolator = null; 59 this.xInterpolator = xInterpolator; 60 this.yInterpolator = yInterpolator; 61 this.startFrame = startFrame; 62 this.endFrame = endFrame; 63 } 64 Keyframe(@uppressWarnings"NullableProblems") LottieComposition composition, @Nullable T startValue, @Nullable T endValue, @Nullable Interpolator interpolator, @Nullable Interpolator xInterpolator, @Nullable Interpolator yInterpolator, float startFrame, @Nullable Float endFrame)65 protected Keyframe(@SuppressWarnings("NullableProblems") LottieComposition composition, 66 @Nullable T startValue, @Nullable T endValue, 67 @Nullable Interpolator interpolator, @Nullable Interpolator xInterpolator, @Nullable Interpolator yInterpolator, 68 float startFrame, @Nullable Float endFrame) { 69 this.composition = composition; 70 this.startValue = startValue; 71 this.endValue = endValue; 72 this.interpolator = interpolator; 73 this.xInterpolator = xInterpolator; 74 this.yInterpolator = yInterpolator; 75 this.startFrame = startFrame; 76 this.endFrame = endFrame; 77 } 78 79 /** 80 * Non-animated value. 81 */ Keyframe(@uppressWarnings"NullableProblems") T value)82 public Keyframe(@SuppressWarnings("NullableProblems") T value) { 83 composition = null; 84 startValue = value; 85 endValue = value; 86 interpolator = null; 87 xInterpolator = null; 88 yInterpolator = null; 89 startFrame = Float.MIN_VALUE; 90 endFrame = Float.MAX_VALUE; 91 } 92 getStartProgress()93 public float getStartProgress() { 94 if (composition == null) { 95 return 0f; 96 } 97 if (startProgress == Float.MIN_VALUE) { 98 startProgress = (startFrame - composition.getStartFrame()) / composition.getDurationFrames(); 99 } 100 return startProgress; 101 } 102 getEndProgress()103 public float getEndProgress() { 104 if (composition == null) { 105 return 1f; 106 } 107 if (endProgress == Float.MIN_VALUE) { 108 if (endFrame == null) { 109 endProgress = 1f; 110 } else { 111 float startProgress = getStartProgress(); 112 float durationFrames = endFrame - startFrame; 113 float durationProgress = durationFrames / composition.getDurationFrames(); 114 endProgress = startProgress + durationProgress; 115 } 116 } 117 return endProgress; 118 } 119 isStatic()120 public boolean isStatic() { 121 return interpolator == null && xInterpolator == null && yInterpolator == null; 122 } 123 containsProgress(@loatRangefrom = 0f, to = 1f) float progress)124 public boolean containsProgress(@FloatRange(from = 0f, to = 1f) float progress) { 125 return progress >= getStartProgress() && progress < getEndProgress(); 126 } 127 128 /** 129 * Optimization to avoid autoboxing. 130 */ getStartValueFloat()131 public float getStartValueFloat() { 132 if (startValueFloat == UNSET_FLOAT) { 133 startValueFloat = (float) (Float) startValue; 134 } 135 return startValueFloat; 136 } 137 138 /** 139 * Optimization to avoid autoboxing. 140 */ getEndValueFloat()141 public float getEndValueFloat() { 142 if (endValueFloat == UNSET_FLOAT) { 143 endValueFloat = (float) (Float) endValue; 144 } 145 return endValueFloat; 146 } 147 148 /** 149 * Optimization to avoid autoboxing. 150 */ getStartValueInt()151 public int getStartValueInt() { 152 if (startValueInt == UNSET_INT) { 153 startValueInt = (int) (Integer) startValue; 154 } 155 return startValueInt; 156 } 157 158 /** 159 * Optimization to avoid autoboxing. 160 */ getEndValueInt()161 public int getEndValueInt() { 162 if (endValueInt == UNSET_INT) { 163 endValueInt = (int) (Integer) endValue; 164 } 165 return endValueInt; 166 } 167 toString()168 @Override public String toString() { 169 return "Keyframe{" + "startValue=" + startValue + 170 ", endValue=" + endValue + 171 ", startFrame=" + startFrame + 172 ", endFrame=" + endFrame + 173 ", interpolator=" + interpolator + 174 '}'; 175 } 176 } 177