1 /*
2 * Copyright 2020 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.compose.animation.core
18
19 import androidx.compose.runtime.State
20 import androidx.compose.runtime.getValue
21 import androidx.compose.runtime.mutableStateOf
22 import androidx.compose.runtime.setValue
23
24 /**
25 * [AnimationState] contains the necessary information to indicate the state of an animation. Once
26 * an [AnimationState] is constructed, it can only be updated/mutated by animations. If there's a
27 * need to mutate some of the fields of an [AnimationState], consider using [copy] functions.
28 *
29 * @param typeConverter [TwoWayConverter] to convert type [T] from and to [AnimationVector]
30 * @param initialValue initial value of the [AnimationState]
31 * @param initialVelocityVector initial velocity of the [AnimationState], null (i.e. no velocity) by
32 * default.
33 * @param lastFrameTimeNanos last frame time of the animation, [AnimationConstants.UnspecifiedTime]
34 * by default
35 * @param finishedTimeNanos the time that the animation finished successfully,
36 * [AnimationConstants.UnspecifiedTime] until then
37 * @param isRunning whether the [AnimationState] is currently being updated by an animation. False
38 * by default
39 */
40 public class AnimationState<T, V : AnimationVector>(
41 public val typeConverter: TwoWayConverter<T, V>,
42 initialValue: T,
43 initialVelocityVector: V? = null,
44 lastFrameTimeNanos: Long = AnimationConstants.UnspecifiedTime,
45 finishedTimeNanos: Long = AnimationConstants.UnspecifiedTime,
46 isRunning: Boolean = false
47 ) : State<T> {
48 /** Current value of the [AnimationState]. */
49 override var value: T by mutableStateOf(initialValue)
50 internal set
51
52 /** Current velocity vector of the [AnimationState]. */
53 public var velocityVector: V =
54 initialVelocityVector?.copy() ?: typeConverter.createZeroVectorFrom(initialValue)
55 internal set
56
57 /**
58 * Last frame time of the animation.
59 *
60 * If the animation has never started, this will be [AnimationConstants.UnspecifiedTime], unless
61 * specified otherwise in the [AnimationState] constructor. [lastFrameTimeNanos] is the frame
62 * time when the animation is last updated, in the [System.nanoTime] timebase. It is also used
63 * for starting a sequential animation in [AnimationState.animateTo]. This allows the sequential
64 * animation to set its start time to when the previous animation is interrupted or finished.
65 */
66 @get:Suppress("MethodNameUnits")
67 public var lastFrameTimeNanos: Long = lastFrameTimeNanos
68 internal set
69
70 /**
71 * The time when the animation finished successfully in the [System.nanoTime] timebase.
72 *
73 * If the animation has never finished (i.e. currently running, interrupted, or never started),
74 * this will be [AnimationConstants.UnspecifiedTime], unless specified otherwise in
75 * [AnimationState] constructor.
76 */
77 @get:Suppress("MethodNameUnits")
78 public var finishedTimeNanos: Long = finishedTimeNanos
79 internal set
80
81 /** Indicates whether the animation is currently running. */
82 public var isRunning: Boolean = isRunning
83 internal set
84
85 /** Velocity of type [T], converted from [velocityVector]. */
86 public val velocity: T
87 get() = typeConverter.convertFromVector(velocityVector)
88
toStringnull89 override fun toString(): String {
90 return "AnimationState(" +
91 "value=$value, " +
92 "velocity=$velocity, " +
93 "isRunning=$isRunning, " +
94 "lastFrameTimeNanos=$lastFrameTimeNanos, " +
95 "finishedTimeNanos=$finishedTimeNanos" +
96 ")"
97 }
98 }
99
100 /**
101 * Indicates whether the given [AnimationState] is for an animation that has finished, indicated by
102 * [AnimationState.finishedTimeNanos] having a specified value.
103 */
104 public val AnimationState<*, *>.isFinished: Boolean
105 get() = finishedTimeNanos != AnimationConstants.UnspecifiedTime
106
107 /**
108 * [AnimationScope] provides all the animation related info specific to an animation run. An
109 * [AnimationScope] will be accessible during an animation.
110 *
111 * @see [AnimationState.animateTo]
112 */
113 public class AnimationScope<T, V : AnimationVector>
114 internal constructor(
115 initialValue: T,
116 /** [TwoWayConverter] to convert type [T] from and to [AnimationVector]. */
117 public val typeConverter: TwoWayConverter<T, V>,
118 initialVelocityVector: V,
119 lastFrameTimeNanos: Long,
120 /** Target value of the animation. */
121 public val targetValue: T,
122 /** Start time of the animation in the [System.nanoTime] timebase. */
123 @get:Suppress("MethodNameUnits") public val startTimeNanos: Long,
124 isRunning: Boolean,
125 private val onCancel: () -> Unit
126 ) {
127 // Externally immutable fields
128 /** Current value of the [AnimationScope]. */
129 public var value: T by mutableStateOf(initialValue)
130 internal set
131
132 /** Current velocity vector of the [AnimationScope]. */
133 public var velocityVector: V = initialVelocityVector.copy()
134 internal set
135
136 /**
137 * Last frame time of the animation.
138 *
139 * If the animation has never started, this will be [AnimationConstants.UnspecifiedTime], unless
140 * specified otherwise in the [AnimationState] constructor. [lastFrameTimeNanos] is the frame
141 * time when the animation is last updated, in the [System.nanoTime] timebase. It is also used
142 * for starting a sequential animation in [AnimationState.animateTo]. This allows the sequential
143 * animation to set its start time to when the previous animation is interrupted or finished.
144 */
145 @get:Suppress("MethodNameUnits")
146 public var lastFrameTimeNanos: Long = lastFrameTimeNanos
147 internal set
148
149 /**
150 * The time when the animation finished successfully in the [System.nanoTime] timebase.
151 *
152 * If the animation has never finished (i.e. currently running, interrupted, or never started),
153 * this will be [AnimationConstants.UnspecifiedTime], unless specified otherwise in
154 * [AnimationState] constructor.
155 */
156 @get:Suppress("MethodNameUnits")
157 public var finishedTimeNanos: Long = AnimationConstants.UnspecifiedTime
158 internal set
159
160 /** Indicates whether the animation is currently running. */
161 public var isRunning: Boolean by mutableStateOf(isRunning)
162 internal set
163
164 /** Velocity of type [T], converted from [velocityVector]. */
165 public val velocity: T
166 get() = typeConverter.convertFromVector(velocityVector)
167
168 /**
169 * Cancels the animation that this [AnimationScope] corresponds to. The scope will not be
170 * updated any more after [cancelAnimation] is called.
171 */
cancelAnimationnull172 public fun cancelAnimation() {
173 isRunning = false
174 onCancel()
175 }
176
177 /**
178 * Creates an [AnimationState] that populates all the fields in [AnimationState] from
179 * [AnimationScope].
180 */
toAnimationStatenull181 public fun toAnimationState(): AnimationState<T, V> =
182 AnimationState(
183 typeConverter,
184 value,
185 velocityVector,
186 lastFrameTimeNanos,
187 finishedTimeNanos,
188 isRunning
189 )
190 }
191
192 /**
193 * Creates a new [AnimationState] from a given [AnimationState]. This function allows some of the
194 * fields to be different in the new [AnimationState].
195 *
196 * @param value value of the [AnimationState], using the value of the given [AnimationState] by
197 * default
198 * @param velocityVector velocity of the [AnimationState], using the velocity of the given
199 * [AnimationState] by default.
200 * @param lastFrameTimeNanos last frame time of the animation, same as the given [AnimationState] by
201 * default
202 * @param finishedTimeNanos the time that the animation finished successfully,
203 * [AnimationConstants.UnspecifiedTime] until then. Default value is the same as the given
204 * [AnimationState].
205 * @param isRunning whether the [AnimationState] is currently being updated by an animation. Same as
206 * the given [AnimationState] by default
207 * @return A new [AnimationState] instance copied from the given instance, with some fields
208 * optionally altered
209 */
210 public fun <T, V : AnimationVector> AnimationState<T, V>.copy(
211 value: T = this.value,
212 velocityVector: V? = this.velocityVector.copy(),
213 lastFrameTimeNanos: Long = this.lastFrameTimeNanos,
214 finishedTimeNanos: Long = this.finishedTimeNanos,
215 isRunning: Boolean = this.isRunning
216 ): AnimationState<T, V> =
217 AnimationState(
218 this.typeConverter,
219 value,
220 velocityVector,
221 lastFrameTimeNanos,
222 finishedTimeNanos,
223 isRunning
224 )
225
226 /**
227 * Creates a new [AnimationState] of Float [value] type from a given [AnimationState] of the same
228 * type. This function allows some of the fields to be different in the new [AnimationState].
229 *
230 * @param value value of the [AnimationState], using the value of the given [AnimationState] by
231 * default
232 * @param velocity velocity of the [AnimationState], using the velocity of the given
233 * [AnimationState] by default.
234 * @param lastFrameTimeNanos last frame time of the animation, same as the given [AnimationState] by
235 * default
236 * @param finishedTimeNanos the time that the animation finished successfully, same as the given
237 * [AnimationState] by default.
238 * @param isRunning whether the [AnimationState] is currently being updated by an animation. Same as
239 * the given [AnimationState] by default
240 * @return A new [AnimationState] instance copied from the given instance, with some fields
241 * optionally altered
242 */
243 public fun AnimationState<Float, AnimationVector1D>.copy(
244 value: Float = this.value,
245 velocity: Float = this.velocityVector.value,
246 lastFrameTimeNanos: Long = this.lastFrameTimeNanos,
247 finishedTimeNanos: Long = this.finishedTimeNanos,
248 isRunning: Boolean = this.isRunning
249 ): AnimationState<Float, AnimationVector1D> =
250 AnimationState(
251 this.typeConverter,
252 value,
253 AnimationVector(velocity),
254 lastFrameTimeNanos,
255 finishedTimeNanos,
256 isRunning
257 )
258
259 /**
260 * Factory method for creating an [AnimationState] for Float [initialValue].
261 *
262 * @param initialValue initial value of the [AnimationState]
263 * @param initialVelocity initial velocity of the [AnimationState], 0 (i.e. no velocity) by default
264 * @param lastFrameTimeNanos last frame time of the animation, [AnimationConstants.UnspecifiedTime]
265 * by default
266 * @param finishedTimeNanos the time that the animation finished successfully,
267 * [AnimationConstants.UnspecifiedTime] by default.
268 * @param isRunning whether the [AnimationState] is currently being updated by an animation. False
269 * by default
270 * @return A new [AnimationState] instance
271 */
272 public fun AnimationState(
273 initialValue: Float,
274 initialVelocity: Float = 0f,
275 lastFrameTimeNanos: Long = AnimationConstants.UnspecifiedTime,
276 finishedTimeNanos: Long = AnimationConstants.UnspecifiedTime,
277 isRunning: Boolean = false
278 ): AnimationState<Float, AnimationVector1D> {
279 return AnimationState(
280 Float.VectorConverter,
281 initialValue,
282 AnimationVector(initialVelocity),
283 lastFrameTimeNanos,
284 finishedTimeNanos,
285 isRunning
286 )
287 }
288
289 /**
290 * Factory method for creating an [AnimationState] with an [initialValue] and an [initialVelocity].
291 *
292 * @param typeConverter [TwoWayConverter] to convert type [T] from and to [AnimationVector]
293 * @param initialValue initial value of the [AnimationState]
294 * @param initialVelocity initial velocity of the [AnimationState]
295 * @param lastFrameTimeNanos last frame time of the animation, [AnimationConstants.UnspecifiedTime]
296 * by default
297 * @param finishedTimeNanos the time that the animation finished successfully,
298 * [AnimationConstants.UnspecifiedTime] by default.
299 * @param isRunning whether the [AnimationState] is currently being updated by an animation. False
300 * by default
301 * @return A new [AnimationState] instance
302 */
AnimationStatenull303 public fun <T, V : AnimationVector> AnimationState(
304 typeConverter: TwoWayConverter<T, V>,
305 initialValue: T,
306 initialVelocity: T,
307 lastFrameTimeNanos: Long = AnimationConstants.UnspecifiedTime,
308 finishedTimeNanos: Long = AnimationConstants.UnspecifiedTime,
309 isRunning: Boolean = false
310 ): AnimationState<T, V> {
311 return AnimationState(
312 typeConverter,
313 initialValue,
314 typeConverter.convertToVector(initialVelocity),
315 lastFrameTimeNanos,
316 finishedTimeNanos,
317 isRunning
318 )
319 }
320
321 /**
322 * Creates an AnimationVector with all the values set to 0 using the provided [TwoWayConverter] and
323 * the [value].
324 *
325 * @return a new AnimationVector instance of type [V].
326 */
createZeroVectorFromnull327 public fun <T, V : AnimationVector> TwoWayConverter<T, V>.createZeroVectorFrom(value: T): V =
328 convertToVector(value).also { it.reset() }
329