在 react-native-reanimated 中继续循环动画
Posted
技术标签:
【中文标题】在 react-native-reanimated 中继续循环动画【英文标题】:Keep looping an animation in react-native-reanimated 【发布时间】:2021-05-15 18:51:19 【问题描述】:我对 react-native
中的动画完全陌生,我正在尝试使用 react-native-reanimated
库创建一个动画脉动按钮。
动画概念对我来说还不是很清楚,但是通过修改其他人的代码,我已经非常接近我想要创建的内容了。
我想让这个脉动的动画连续。目前,它会跳动然后停止。我很感激这方面的一些帮助。我将代码和零食都包括在内,以便您查看正在运行的示例。请记住,我只是修改了别人的代码,所以我确信这段代码中有些东西是不必要的。我正在学习这个按钮。
这是小吃的链接:https://snack.expo.io/@imsam67/reanimated-test
这是代码:
import React, Component from 'react';
import StyleSheet, View from 'react-native';
import Animated from 'react-native-reanimated';
const
divide,
set,
cond,
startClock,
stopClock,
clockRunning,
block,
spring,
debug,
Value,
Clock,
= Animated;
function runSpring(clock, value, dest)
const state =
finished: new Value(0),
velocity: new Value(0),
position: new Value(0),
time: new Value(0),
;
const config =
toValue: new Value(0),
damping: 10,
mass: 5,
stiffness: 101.6,
overshootClamping: false,
restSpeedThreshold: 0.001,
restDisplacementThreshold: 0.001,
;
return block([
cond(clockRunning(clock), 0, [
set(state.finished, 0),
set(state.time, 0),
set(state.position, value),
set(state.velocity, -2500),
set(config.toValue, dest),
startClock(clock),
]),
spring(clock, state, config),
cond(state.finished, debug('stop clock', stopClock(clock))),
state.position,
]);
export default class Example extends Component
constructor(props)
super(props);
const clock = new Clock();
this._trans = runSpring(clock, 10, 150);
componentDidMount()
render()
return (
<View style=styles.container>
<Animated.View
style=[styles.circle, borderWidth: divide(this._trans, 5) ]>
</Animated.View>
</View>
);
const BOX_SIZE = 100;
const styles = StyleSheet.create(
container:
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'black',
,
circle:
backgroundColor: "white",
borderColor: "red",
borderRadius: 150,
height: 150,
width: 150
);
【问题讨论】:
【参考方案1】:另一种使用重新激活的 1.x.x 更可控的方法是:
const [clock] = useState(() => new Clock());
const loopingValue = useMemo(() =>
const state =
finished: new Value(0),
position: new Value(0),
time: new Value(0),
frameTime: new Value(0),
;
const config =
duration: new Value(2000),
toValue: new Value(1),
easing: Easing.linear,
;
const value = block([
// start right away
startClock(clock),
// process your state
timing(clock, state, config),
// when over (processed by timing at the end)
cond(state.finished, [
// we stop
stopClock(clock),
// set flag ready to be restarted
set(state.finished, 0),
// same value as the initial defined in the state creation
set(state.position, 0),
// very important to reset this ones !!! as mentioned in the doc about timing is saying
set(state.time, 0),
set(state.frameTime, 0),
// and we restart
startClock(clock),
]),
state.position,
]);
return interpolate(value,
inputRange: [0, 0.5, 1],
outputRange: [0, 1, 0],
);
, [clock]);
这里的很多代码都是从 github 线程中复制的:https://github.com/software-mansion/react-native-reanimated/issues/162
【讨论】:
【参考方案2】:让此动画循环播放的一种快速方法是将阻尼设置为 0。这将使弹簧动画无限期地运行。
const config =
toValue: new Value(0),
damping: 0, // changed to 0
mass: 5
stiffness: 101.6,
overshootClamping: false,
restSpeedThreshold: 0.001,
restDisplacementThreshold: 0.001,
;
但您可能希望更改 borderWidth
样式以除以更大的数字,以防止边界半径超出。
<Animated.View
style=[styles.circle, borderWidth: divide(this._trans, 25) ]>
</Animated.View>
你可以找到修改后的小吃here。
对于这样的重复动画,您还可以考虑使用Lottie,它实现起来要简单得多,但灵活性较差。
另外,您可以使用 react native Animations 中的 loop 来设置边框半径。
【讨论】:
感谢您的帮助。但是注意到一些事情:如果您选择网络,它完全按照我想要的方式工作,但在ios
或 android
上运行它不会产生循环动画。知道为什么吗?
另外,我想在react-native-reanimated
中处理这个动画的原因是因为它在本机UI
线程而不是JS
线程中运行。特别是在这个特定动画的情况下,在JS
线程中运行它会产生不好的结果,即丢帧。我不确定,但我认为Lottie
和Loop
也在JS
线程中运行,不是吗?
我刚刚在 Android 和 iOS 上测试了零食,它似乎在循环播放?不完全确定为什么它不起作用。您可以尝试进行一些小编辑以触发重新运行,这可能会解决问题。
至于性能,在 Lottie 中,您将提供一个 JSON 文件,然后将其传递给本机代码。这应该会提供不错的性能,因为它不在本机线程上运行。对于动画,您可以设置 useNativeDriver 以在原生 UI 中运行更改,但您只能修改一些样式属性(我不确定是否包含边框半径,但您可以通过转换圆形来模拟相同的效果) .
所以,Lottie 确实在本机线程中运行!很高兴知道。谢谢你让我知道!我猜对于像滚动或按钮动画这样的典型动画,性能差异可能不那么明显,但是像这样的按钮会保持脉动,使用 JS 线程将是一个糟糕的主意。以上是关于在 react-native-reanimated 中继续循环动画的主要内容,如果未能解决你的问题,请参考以下文章
在本机 ios 中找不到模块“react-native-reanimated/plugin”