forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Kotlinify FrameBasedAnimationDriver (facebook#45764)
Summary: Pull Request resolved: facebook#45764 # Changelog: [Internal] - As in the title. Differential Revision: D60348765
- Loading branch information
1 parent
96f5151
commit f35560b
Showing
2 changed files
with
111 additions
and
114 deletions.
There are no files selected for viewing
114 changes: 0 additions & 114 deletions
114
...ive/ReactAndroid/src/main/java/com/facebook/react/animated/FrameBasedAnimationDriver.java
This file was deleted.
Oops, something went wrong.
111 changes: 111 additions & 0 deletions
111
...ative/ReactAndroid/src/main/java/com/facebook/react/animated/FrameBasedAnimationDriver.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.react.animated | ||
|
||
import com.facebook.common.logging.FLog | ||
import com.facebook.react.bridge.ReadableMap | ||
import com.facebook.react.bridge.ReadableType | ||
import com.facebook.react.common.ReactConstants | ||
import com.facebook.react.common.build.ReactBuildConfig | ||
|
||
/** | ||
* Implementation of [AnimationDriver] which provides a support for simple time-based animations | ||
* that are pre-calculate on the JS side. For each animation frame JS provides a value from 0 to 1 | ||
* that indicates a progress of the animation at that frame. | ||
*/ | ||
internal class FrameBasedAnimationDriver(config: ReadableMap) : AnimationDriver() { | ||
private var startFrameTimeNanos: Long = -1 | ||
private var frames: DoubleArray = DoubleArray(0) | ||
private var toValue = 0.0 | ||
private var fromValue = 0.0 | ||
private var iterations = 1 | ||
private var currentLoop = 1 | ||
private var logCount = 0 | ||
|
||
init { | ||
resetConfig(config) | ||
} | ||
|
||
override fun resetConfig(config: ReadableMap) { | ||
val framesConfig = config.getArray("frames") | ||
if (framesConfig != null) { | ||
val numberOfFrames = framesConfig.size() | ||
if (frames.size != numberOfFrames) { | ||
frames = DoubleArray(numberOfFrames) | ||
} | ||
for (i in 0 until numberOfFrames) { | ||
frames[i] = framesConfig.getDouble(i) | ||
} | ||
} | ||
toValue = | ||
if (config.hasKey("toValue")) { | ||
if (config.getType("toValue") == ReadableType.Number) config.getDouble("toValue") else 0.0 | ||
} else { | ||
0.0 | ||
} | ||
iterations = | ||
if (config.hasKey("iterations")) { | ||
if (config.getType("iterations") == ReadableType.Number) config.getInt("iterations") | ||
else 1 | ||
} else { | ||
1 | ||
} | ||
currentLoop = 1 | ||
mHasFinished = iterations == 0 | ||
startFrameTimeNanos = -1 | ||
} | ||
|
||
override fun runAnimationStep(frameTimeNanos: Long) { | ||
if (startFrameTimeNanos < 0) { | ||
startFrameTimeNanos = frameTimeNanos | ||
if (currentLoop == 1) { | ||
// initiate start value when animation runs for the first time | ||
fromValue = mAnimatedValue.nodeValue | ||
} | ||
} | ||
val timeFromStartMillis = (frameTimeNanos - startFrameTimeNanos) / 1000000 | ||
val frameIndex = Math.round(timeFromStartMillis / FRAME_TIME_MILLIS).toInt() | ||
if (frameIndex < 0) { | ||
val message = | ||
("Calculated frame index should never be lower than 0. Called with frameTimeNanos " + | ||
frameTimeNanos + | ||
" and mStartFrameTimeNanos " + | ||
startFrameTimeNanos) | ||
check(!ReactBuildConfig.DEBUG) { message } | ||
if (logCount < 100) { | ||
FLog.w(ReactConstants.TAG, message) | ||
logCount++ | ||
} | ||
return | ||
} else if (mHasFinished) { | ||
// nothing to do here | ||
return | ||
} | ||
val nextValue: Double | ||
if (frameIndex >= frames.size - 1) { | ||
if (iterations == -1 || currentLoop < iterations) { | ||
// Use last frame value, just in case it's different from mToValue | ||
nextValue = fromValue + frames[frames.size - 1] * (toValue - fromValue) | ||
startFrameTimeNanos = -1 | ||
currentLoop++ | ||
} else { | ||
// animation has completed, no more frames left | ||
nextValue = toValue | ||
mHasFinished = true | ||
} | ||
} else { | ||
nextValue = fromValue + frames[frameIndex] * (toValue - fromValue) | ||
} | ||
mAnimatedValue.nodeValue = nextValue | ||
} | ||
|
||
companion object { | ||
// 60FPS | ||
private const val FRAME_TIME_MILLIS = 1000.0 / 60.0 | ||
} | ||
} |