react-native-ease 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,541 @@
1
+ package com.ease
2
+
3
+ import android.animation.Animator
4
+ import android.animation.AnimatorListenerAdapter
5
+ import android.animation.ObjectAnimator
6
+ import android.content.Context
7
+ import android.graphics.Outline
8
+ import android.view.View
9
+ import android.view.ViewOutlineProvider
10
+ import android.view.animation.PathInterpolator
11
+ import androidx.dynamicanimation.animation.DynamicAnimation
12
+ import androidx.dynamicanimation.animation.SpringAnimation
13
+ import androidx.dynamicanimation.animation.SpringForce
14
+ import com.facebook.react.views.view.ReactViewGroup
15
+ import kotlin.math.sqrt
16
+
17
+ class EaseView(context: Context) : ReactViewGroup(context) {
18
+
19
+ // --- Previous animate values (for change detection) ---
20
+ private var prevOpacity: Float? = null
21
+ private var prevTranslateX: Float? = null
22
+ private var prevTranslateY: Float? = null
23
+ private var prevScaleX: Float? = null
24
+ private var prevScaleY: Float? = null
25
+ private var prevRotate: Float? = null
26
+ private var prevRotateX: Float? = null
27
+ private var prevRotateY: Float? = null
28
+ private var prevBorderRadius: Float? = null
29
+
30
+ // --- First mount tracking ---
31
+ private var isFirstMount: Boolean = true
32
+
33
+ // --- Transition config (set by ViewManager) ---
34
+ var transitionType: String = "timing"
35
+ var transitionDuration: Int = 300
36
+ var transitionEasingBezier: FloatArray = floatArrayOf(0.42f, 0f, 0.58f, 1.0f)
37
+ var transitionDamping: Float = 15.0f
38
+ var transitionStiffness: Float = 120.0f
39
+ var transitionMass: Float = 1.0f
40
+ var transitionLoop: String = "none"
41
+
42
+ // --- Transform origin (0–1 fractions) ---
43
+ var transformOriginX: Float = 0.5f
44
+ set(value) {
45
+ field = value
46
+ applyTransformOrigin()
47
+ }
48
+ var transformOriginY: Float = 0.5f
49
+ set(value) {
50
+ field = value
51
+ applyTransformOrigin()
52
+ }
53
+
54
+ // --- Border radius (hardware-accelerated via outline clipping) ---
55
+ // Animated via ObjectAnimator("borderRadius") — setter invalidates outline each frame.
56
+ private var _borderRadius: Float = 0f
57
+
58
+ fun getBorderRadius(): Float = _borderRadius
59
+ fun setBorderRadius(value: Float) {
60
+ if (_borderRadius != value) {
61
+ _borderRadius = value
62
+ if (value > 0f) {
63
+ clipToOutline = true
64
+ } else {
65
+ clipToOutline = false
66
+ }
67
+ invalidateOutline()
68
+ }
69
+ }
70
+
71
+ // --- Hardware layer ---
72
+ var useHardwareLayer: Boolean = false
73
+
74
+ // --- Event callback ---
75
+ var onTransitionEnd: ((finished: Boolean) -> Unit)? = null
76
+ private var activeAnimationCount: Int = 0
77
+ private var animationBatchId: Int = 0
78
+ private var pendingBatchAnimationCount: Int = 0
79
+ private var anyInterrupted: Boolean = false
80
+ private var savedLayerType: Int = View.LAYER_TYPE_NONE
81
+
82
+ // --- Initial animate values (set by ViewManager) ---
83
+ var initialAnimateOpacity: Float = 1.0f
84
+ var initialAnimateTranslateX: Float = 0.0f
85
+ var initialAnimateTranslateY: Float = 0.0f
86
+ var initialAnimateScaleX: Float = 1.0f
87
+ var initialAnimateScaleY: Float = 1.0f
88
+ var initialAnimateRotate: Float = 0.0f
89
+ var initialAnimateRotateX: Float = 0.0f
90
+ var initialAnimateRotateY: Float = 0.0f
91
+ var initialAnimateBorderRadius: Float = 0.0f
92
+
93
+ // --- Pending animate values (buffered per-view, applied in onAfterUpdateTransaction) ---
94
+ var pendingOpacity: Float = 1.0f
95
+ var pendingTranslateX: Float = 0.0f
96
+ var pendingTranslateY: Float = 0.0f
97
+ var pendingScaleX: Float = 1.0f
98
+ var pendingScaleY: Float = 1.0f
99
+ var pendingRotate: Float = 0.0f
100
+ var pendingRotateX: Float = 0.0f
101
+ var pendingRotateY: Float = 0.0f
102
+ var pendingBorderRadius: Float = 0.0f
103
+
104
+ // --- Running animations ---
105
+ private val runningAnimators = mutableMapOf<String, ObjectAnimator>()
106
+ private val runningSpringAnimations = mutableMapOf<DynamicAnimation.ViewProperty, SpringAnimation>()
107
+
108
+ // --- Animated properties bitmask (set by ViewManager) ---
109
+ var animatedProperties: Int = 0
110
+
111
+ // --- Easing interpolators (lazy singletons shared across all instances) ---
112
+ companion object {
113
+ // Bitmask flags — must match JS constants
114
+ const val MASK_OPACITY = 1 shl 0
115
+ const val MASK_TRANSLATE_X = 1 shl 1
116
+ const val MASK_TRANSLATE_Y = 1 shl 2
117
+ const val MASK_SCALE_X = 1 shl 3
118
+ const val MASK_SCALE_Y = 1 shl 4
119
+ const val MASK_ROTATE = 1 shl 5
120
+ const val MASK_ROTATE_X = 1 shl 6
121
+ const val MASK_ROTATE_Y = 1 shl 7
122
+ const val MASK_BORDER_RADIUS = 1 shl 8
123
+ }
124
+
125
+ init {
126
+ // Set camera distance for 3D perspective rotations (rotateX/rotateY)
127
+ cameraDistance = resources.displayMetrics.density * 850f
128
+
129
+ // ViewOutlineProvider reads _borderRadius dynamically — set once, invalidated on each frame.
130
+ outlineProvider = object : ViewOutlineProvider() {
131
+ override fun getOutline(view: View, outline: Outline) {
132
+ outline.setRoundRect(0, 0, view.width, view.height, _borderRadius)
133
+ }
134
+ }
135
+ }
136
+
137
+ // --- Hardware layer management ---
138
+
139
+ private fun onEaseAnimationStart() {
140
+ if (activeAnimationCount == 0 && useHardwareLayer) {
141
+ savedLayerType = layerType
142
+ setLayerType(View.LAYER_TYPE_HARDWARE, null)
143
+ }
144
+ activeAnimationCount++
145
+ }
146
+
147
+ private fun onEaseAnimationEnd() {
148
+ activeAnimationCount--
149
+ if (activeAnimationCount <= 0) {
150
+ activeAnimationCount = 0
151
+ if (useHardwareLayer && layerType == View.LAYER_TYPE_HARDWARE) {
152
+ setLayerType(savedLayerType, null)
153
+ }
154
+ }
155
+ }
156
+
157
+ // --- Transform origin ---
158
+
159
+ fun applyTransformOrigin() {
160
+ if (width > 0 && height > 0) {
161
+ pivotX = width * transformOriginX
162
+ pivotY = height * transformOriginY
163
+ }
164
+ }
165
+
166
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
167
+ super.onLayout(changed, left, top, right, bottom)
168
+ applyTransformOrigin()
169
+ }
170
+
171
+ fun applyPendingAnimateValues() {
172
+ applyAnimateValues(pendingOpacity, pendingTranslateX, pendingTranslateY, pendingScaleX, pendingScaleY, pendingRotate, pendingRotateX, pendingRotateY, pendingBorderRadius)
173
+ }
174
+
175
+ private fun applyAnimateValues(
176
+ opacity: Float,
177
+ translateX: Float,
178
+ translateY: Float,
179
+ scaleX: Float,
180
+ scaleY: Float,
181
+ rotate: Float,
182
+ rotateX: Float,
183
+ rotateY: Float,
184
+ borderRadius: Float
185
+ ) {
186
+ if (pendingBatchAnimationCount > 0) {
187
+ onTransitionEnd?.invoke(false)
188
+ }
189
+
190
+ animationBatchId++
191
+ pendingBatchAnimationCount = 0
192
+ anyInterrupted = false
193
+
194
+ // Bitmask: which properties are animated. Non-animated = let style handle.
195
+ val mask = animatedProperties
196
+
197
+ if (isFirstMount) {
198
+ isFirstMount = false
199
+
200
+ val hasInitialAnimation =
201
+ (mask and MASK_OPACITY != 0 && initialAnimateOpacity != opacity) ||
202
+ (mask and MASK_TRANSLATE_X != 0 && initialAnimateTranslateX != translateX) ||
203
+ (mask and MASK_TRANSLATE_Y != 0 && initialAnimateTranslateY != translateY) ||
204
+ (mask and MASK_SCALE_X != 0 && initialAnimateScaleX != scaleX) ||
205
+ (mask and MASK_SCALE_Y != 0 && initialAnimateScaleY != scaleY) ||
206
+ (mask and MASK_ROTATE != 0 && initialAnimateRotate != rotate) ||
207
+ (mask and MASK_ROTATE_X != 0 && initialAnimateRotateX != rotateX) ||
208
+ (mask and MASK_ROTATE_Y != 0 && initialAnimateRotateY != rotateY) ||
209
+ (mask and MASK_BORDER_RADIUS != 0 && initialAnimateBorderRadius != borderRadius)
210
+
211
+ if (hasInitialAnimation) {
212
+ // Set initial values for animated properties
213
+ if (mask and MASK_OPACITY != 0) this.alpha = initialAnimateOpacity
214
+ if (mask and MASK_TRANSLATE_X != 0) this.translationX = initialAnimateTranslateX
215
+ if (mask and MASK_TRANSLATE_Y != 0) this.translationY = initialAnimateTranslateY
216
+ if (mask and MASK_SCALE_X != 0) this.scaleX = initialAnimateScaleX
217
+ if (mask and MASK_SCALE_Y != 0) this.scaleY = initialAnimateScaleY
218
+ if (mask and MASK_ROTATE != 0) this.rotation = initialAnimateRotate
219
+ if (mask and MASK_ROTATE_X != 0) this.rotationX = initialAnimateRotateX
220
+ if (mask and MASK_ROTATE_Y != 0) this.rotationY = initialAnimateRotateY
221
+ if (mask and MASK_BORDER_RADIUS != 0) setBorderRadius(initialAnimateBorderRadius)
222
+
223
+ // Animate properties that differ from initial to target
224
+ if (mask and MASK_OPACITY != 0 && initialAnimateOpacity != opacity) {
225
+ animateProperty("alpha", DynamicAnimation.ALPHA, initialAnimateOpacity, opacity, loop = true)
226
+ }
227
+ if (mask and MASK_TRANSLATE_X != 0 && initialAnimateTranslateX != translateX) {
228
+ animateProperty("translationX", DynamicAnimation.TRANSLATION_X, initialAnimateTranslateX, translateX, loop = true)
229
+ }
230
+ if (mask and MASK_TRANSLATE_Y != 0 && initialAnimateTranslateY != translateY) {
231
+ animateProperty("translationY", DynamicAnimation.TRANSLATION_Y, initialAnimateTranslateY, translateY, loop = true)
232
+ }
233
+ if (mask and MASK_SCALE_X != 0 && initialAnimateScaleX != scaleX) {
234
+ animateProperty("scaleX", DynamicAnimation.SCALE_X, initialAnimateScaleX, scaleX, loop = true)
235
+ }
236
+ if (mask and MASK_SCALE_Y != 0 && initialAnimateScaleY != scaleY) {
237
+ animateProperty("scaleY", DynamicAnimation.SCALE_Y, initialAnimateScaleY, scaleY, loop = true)
238
+ }
239
+ if (mask and MASK_ROTATE != 0 && initialAnimateRotate != rotate) {
240
+ animateProperty("rotation", DynamicAnimation.ROTATION, initialAnimateRotate, rotate, loop = true)
241
+ }
242
+ if (mask and MASK_ROTATE_X != 0 && initialAnimateRotateX != rotateX) {
243
+ animateProperty("rotationX", DynamicAnimation.ROTATION_X, initialAnimateRotateX, rotateX, loop = true)
244
+ }
245
+ if (mask and MASK_ROTATE_Y != 0 && initialAnimateRotateY != rotateY) {
246
+ animateProperty("rotationY", DynamicAnimation.ROTATION_Y, initialAnimateRotateY, rotateY, loop = true)
247
+ }
248
+ if (mask and MASK_BORDER_RADIUS != 0 && initialAnimateBorderRadius != borderRadius) {
249
+ animateProperty("borderRadius", null, initialAnimateBorderRadius, borderRadius, loop = true)
250
+ }
251
+ } else {
252
+ // No initial animation — set target values directly (skip non-animated)
253
+ if (mask and MASK_OPACITY != 0) this.alpha = opacity
254
+ if (mask and MASK_TRANSLATE_X != 0) this.translationX = translateX
255
+ if (mask and MASK_TRANSLATE_Y != 0) this.translationY = translateY
256
+ if (mask and MASK_SCALE_X != 0) this.scaleX = scaleX
257
+ if (mask and MASK_SCALE_Y != 0) this.scaleY = scaleY
258
+ if (mask and MASK_ROTATE != 0) this.rotation = rotate
259
+ if (mask and MASK_ROTATE_X != 0) this.rotationX = rotateX
260
+ if (mask and MASK_ROTATE_Y != 0) this.rotationY = rotateY
261
+ if (mask and MASK_BORDER_RADIUS != 0) setBorderRadius(borderRadius)
262
+ }
263
+ } else if (transitionType == "none") {
264
+ // No transition — set values immediately, cancel running animations
265
+ cancelAllAnimations()
266
+ if (mask and MASK_OPACITY != 0) this.alpha = opacity
267
+ if (mask and MASK_TRANSLATE_X != 0) this.translationX = translateX
268
+ if (mask and MASK_TRANSLATE_Y != 0) this.translationY = translateY
269
+ if (mask and MASK_SCALE_X != 0) this.scaleX = scaleX
270
+ if (mask and MASK_SCALE_Y != 0) this.scaleY = scaleY
271
+ if (mask and MASK_ROTATE != 0) this.rotation = rotate
272
+ if (mask and MASK_ROTATE_X != 0) this.rotationX = rotateX
273
+ if (mask and MASK_ROTATE_Y != 0) this.rotationY = rotateY
274
+ if (mask and MASK_BORDER_RADIUS != 0) setBorderRadius(borderRadius)
275
+ onTransitionEnd?.invoke(true)
276
+ } else {
277
+ // Subsequent updates: animate changed properties (skip non-animated)
278
+ if (prevOpacity != null && mask and MASK_OPACITY != 0 && prevOpacity != opacity) {
279
+ val from = getCurrentValue("alpha")
280
+ animateProperty("alpha", DynamicAnimation.ALPHA, from, opacity)
281
+ }
282
+
283
+ if (prevTranslateX != null && mask and MASK_TRANSLATE_X != 0 && prevTranslateX != translateX) {
284
+ val from = getCurrentValue("translationX")
285
+ animateProperty("translationX", DynamicAnimation.TRANSLATION_X, from, translateX)
286
+ }
287
+
288
+ if (prevTranslateY != null && mask and MASK_TRANSLATE_Y != 0 && prevTranslateY != translateY) {
289
+ val from = getCurrentValue("translationY")
290
+ animateProperty("translationY", DynamicAnimation.TRANSLATION_Y, from, translateY)
291
+ }
292
+
293
+ if (prevScaleX != null && mask and MASK_SCALE_X != 0 && prevScaleX != scaleX) {
294
+ val from = getCurrentValue("scaleX")
295
+ animateProperty("scaleX", DynamicAnimation.SCALE_X, from, scaleX)
296
+ }
297
+
298
+ if (prevScaleY != null && mask and MASK_SCALE_Y != 0 && prevScaleY != scaleY) {
299
+ val from = getCurrentValue("scaleY")
300
+ animateProperty("scaleY", DynamicAnimation.SCALE_Y, from, scaleY)
301
+ }
302
+
303
+ if (prevRotate != null && mask and MASK_ROTATE != 0 && prevRotate != rotate) {
304
+ val from = getCurrentValue("rotation")
305
+ animateProperty("rotation", DynamicAnimation.ROTATION, from, rotate)
306
+ }
307
+
308
+ if (prevRotateX != null && mask and MASK_ROTATE_X != 0 && prevRotateX != rotateX) {
309
+ val from = getCurrentValue("rotationX")
310
+ animateProperty("rotationX", DynamicAnimation.ROTATION_X, from, rotateX)
311
+ }
312
+
313
+ if (prevRotateY != null && mask and MASK_ROTATE_Y != 0 && prevRotateY != rotateY) {
314
+ val from = getCurrentValue("rotationY")
315
+ animateProperty("rotationY", DynamicAnimation.ROTATION_Y, from, rotateY)
316
+ }
317
+
318
+ if (prevBorderRadius != null && mask and MASK_BORDER_RADIUS != 0 && prevBorderRadius != borderRadius) {
319
+ val from = getCurrentValue("borderRadius")
320
+ animateProperty("borderRadius", null, from, borderRadius)
321
+ }
322
+ }
323
+
324
+ prevOpacity = opacity
325
+ prevTranslateX = translateX
326
+ prevTranslateY = translateY
327
+ prevScaleX = scaleX
328
+ prevScaleY = scaleY
329
+ prevRotate = rotate
330
+ prevRotateX = rotateX
331
+ prevRotateY = rotateY
332
+ prevBorderRadius = borderRadius
333
+ }
334
+
335
+ private fun getCurrentValue(propertyName: String): Float = when (propertyName) {
336
+ "alpha" -> this.alpha
337
+ "translationX" -> this.translationX
338
+ "translationY" -> this.translationY
339
+ "scaleX" -> this.scaleX
340
+ "scaleY" -> this.scaleY
341
+ "rotation" -> this.rotation
342
+ "rotationX" -> this.rotationX
343
+ "rotationY" -> this.rotationY
344
+ "borderRadius" -> getBorderRadius()
345
+ else -> 0f
346
+ }
347
+
348
+ private fun animateProperty(
349
+ propertyName: String,
350
+ viewProperty: DynamicAnimation.ViewProperty?,
351
+ fromValue: Float,
352
+ toValue: Float,
353
+ loop: Boolean = false
354
+ ) {
355
+ if (transitionType == "spring" && viewProperty != null) {
356
+ animateSpring(viewProperty, toValue)
357
+ } else {
358
+ animateTiming(propertyName, fromValue, toValue, loop)
359
+ }
360
+ }
361
+
362
+ private fun animateTiming(propertyName: String, fromValue: Float, toValue: Float, loop: Boolean = false) {
363
+ cancelSpringForProperty(propertyName)
364
+ runningAnimators[propertyName]?.cancel()
365
+
366
+ val batchId = animationBatchId
367
+ pendingBatchAnimationCount++
368
+
369
+ val animator = ObjectAnimator.ofFloat(this, propertyName, fromValue, toValue).apply {
370
+ duration = transitionDuration.toLong()
371
+ interpolator = PathInterpolator(
372
+ transitionEasingBezier[0], transitionEasingBezier[1],
373
+ transitionEasingBezier[2], transitionEasingBezier[3]
374
+ )
375
+ if (loop && transitionLoop != "none") {
376
+ repeatCount = ObjectAnimator.INFINITE
377
+ repeatMode = if (transitionLoop == "reverse") {
378
+ ObjectAnimator.REVERSE
379
+ } else {
380
+ ObjectAnimator.RESTART
381
+ }
382
+ }
383
+ addListener(object : AnimatorListenerAdapter() {
384
+ private var cancelled = false
385
+ override fun onAnimationStart(animation: Animator) {
386
+ this@EaseView.onEaseAnimationStart()
387
+ }
388
+ override fun onAnimationCancel(animation: Animator) {
389
+ cancelled = true
390
+ }
391
+ override fun onAnimationEnd(animation: Animator) {
392
+ this@EaseView.onEaseAnimationEnd()
393
+ if (batchId == animationBatchId) {
394
+ if (cancelled) anyInterrupted = true
395
+ pendingBatchAnimationCount--
396
+ if (pendingBatchAnimationCount <= 0) {
397
+ onTransitionEnd?.invoke(!anyInterrupted)
398
+ }
399
+ }
400
+ }
401
+ })
402
+ }
403
+
404
+ runningAnimators[propertyName] = animator
405
+ animator.start()
406
+ }
407
+
408
+ private fun animateSpring(viewProperty: DynamicAnimation.ViewProperty, toValue: Float) {
409
+ cancelTimingForViewProperty(viewProperty)
410
+
411
+ val existingSpring = runningSpringAnimations[viewProperty]
412
+ if (existingSpring != null && existingSpring.isRunning) {
413
+ existingSpring.animateToFinalPosition(toValue)
414
+ return
415
+ }
416
+
417
+ val batchId = animationBatchId
418
+ pendingBatchAnimationCount++
419
+
420
+ val dampingRatio = (transitionDamping / (2.0f * sqrt(transitionStiffness * transitionMass)))
421
+ .coerceAtLeast(0.01f)
422
+
423
+ val spring = SpringAnimation(this, viewProperty).apply {
424
+ spring = SpringForce(toValue).apply {
425
+ this.dampingRatio = dampingRatio
426
+ this.stiffness = transitionStiffness
427
+ }
428
+ addUpdateListener { _, _, _ ->
429
+ // First update — enable hardware layer
430
+ if (activeAnimationCount == 0) {
431
+ this@EaseView.onEaseAnimationStart()
432
+ }
433
+ }
434
+ addEndListener { _, canceled, _, _ ->
435
+ this@EaseView.onEaseAnimationEnd()
436
+ if (batchId == animationBatchId) {
437
+ if (canceled) anyInterrupted = true
438
+ pendingBatchAnimationCount--
439
+ if (pendingBatchAnimationCount <= 0) {
440
+ onTransitionEnd?.invoke(!anyInterrupted)
441
+ }
442
+ }
443
+ }
444
+ }
445
+
446
+ onEaseAnimationStart()
447
+ runningSpringAnimations[viewProperty] = spring
448
+ spring.start()
449
+ }
450
+
451
+ private fun cancelAllAnimations() {
452
+ for (animator in runningAnimators.values) {
453
+ animator.cancel()
454
+ }
455
+ runningAnimators.clear()
456
+ for (spring in runningSpringAnimations.values) {
457
+ if (spring.isRunning) {
458
+ spring.cancel()
459
+ }
460
+ }
461
+ runningSpringAnimations.clear()
462
+ }
463
+
464
+ private fun cancelTimingForViewProperty(viewProperty: DynamicAnimation.ViewProperty) {
465
+ val propertyName = when (viewProperty) {
466
+ DynamicAnimation.ALPHA -> "alpha"
467
+ DynamicAnimation.TRANSLATION_X -> "translationX"
468
+ DynamicAnimation.TRANSLATION_Y -> "translationY"
469
+ DynamicAnimation.SCALE_X -> "scaleX"
470
+ DynamicAnimation.SCALE_Y -> "scaleY"
471
+ DynamicAnimation.ROTATION -> "rotation"
472
+ DynamicAnimation.ROTATION_X -> "rotationX"
473
+ DynamicAnimation.ROTATION_Y -> "rotationY"
474
+ else -> return
475
+ }
476
+ runningAnimators[propertyName]?.cancel()
477
+ runningAnimators.remove(propertyName)
478
+ }
479
+
480
+ private fun cancelSpringForProperty(propertyName: String) {
481
+ val viewProperty = when (propertyName) {
482
+ "alpha" -> DynamicAnimation.ALPHA
483
+ "translationX" -> DynamicAnimation.TRANSLATION_X
484
+ "translationY" -> DynamicAnimation.TRANSLATION_Y
485
+ "scaleX" -> DynamicAnimation.SCALE_X
486
+ "scaleY" -> DynamicAnimation.SCALE_Y
487
+ "rotation" -> DynamicAnimation.ROTATION
488
+ "rotationX" -> DynamicAnimation.ROTATION_X
489
+ "rotationY" -> DynamicAnimation.ROTATION_Y
490
+ else -> return
491
+ }
492
+ runningSpringAnimations[viewProperty]?.let { spring ->
493
+ if (spring.isRunning) {
494
+ spring.cancel()
495
+ }
496
+ }
497
+ runningSpringAnimations.remove(viewProperty)
498
+ }
499
+
500
+ fun cleanup() {
501
+ for (animator in runningAnimators.values) {
502
+ animator.cancel()
503
+ }
504
+ runningAnimators.clear()
505
+
506
+ for (spring in runningSpringAnimations.values) {
507
+ if (spring.isRunning) {
508
+ spring.cancel()
509
+ }
510
+ }
511
+ runningSpringAnimations.clear()
512
+
513
+ if (activeAnimationCount > 0 && layerType == View.LAYER_TYPE_HARDWARE) {
514
+ setLayerType(savedLayerType, null)
515
+ }
516
+ activeAnimationCount = 0
517
+
518
+ prevOpacity = null
519
+ prevTranslateX = null
520
+ prevTranslateY = null
521
+ prevScaleX = null
522
+ prevScaleY = null
523
+ prevRotate = null
524
+ prevRotateX = null
525
+ prevRotateY = null
526
+ prevBorderRadius = null
527
+
528
+ this.alpha = 1f
529
+ this.translationX = 0f
530
+ this.translationY = 0f
531
+ this.scaleX = 1f
532
+ this.scaleY = 1f
533
+ this.rotation = 0f
534
+ this.rotationX = 0f
535
+ this.rotationY = 0f
536
+ setBorderRadius(0f)
537
+
538
+ isFirstMount = true
539
+ transitionLoop = "none"
540
+ }
541
+ }