在 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 来设置边框半径。

【讨论】:

感谢您的帮助。但是注意到一些事情:如果您选择网络,它完全按照我想要的方式工作,但在 iosandroid 上运行它不会产生循环动画。知道为什么吗? 另外,我想在react-native-reanimated 中处理这个动画的原因是因为它在本机UI 线程而不是JS 线程中运行。特别是在这个特定动画的情况下,在JS 线程中运行它会产生不好的结果,即丢帧。我不确定,但我认为LottieLoop 也在JS 线程中运行,不是吗? 我刚刚在 Android 和 iOS 上测试了零食,它似乎在循环播放?不完全确定为什么它不起作用。您可以尝试进行一些小编辑以触发重新运行,这可能会解决问题。 至于性能,在 Lottie 中,您将提供一个 JSON 文件,然后将其传递给本机代码。这应该会提供不错的性能,因为它不在本机线程上运行。对于动画,您可以设置 useNativeDriver 以在原生 UI 中运行更改,但您只能修改一些样式属性(我不确定是否包含边框半径,但您可以通过转换圆形来模拟相同的效果) . 所以,Lottie 确实在本机线程中运行!很高兴知道。谢谢你让我知道!我猜对于像滚动或按钮动画这样的典型动画,性能差异可能不那么明显,但是像这样的按钮会保持脉动,使用 JS 线程将是一个糟糕的主意。

以上是关于在 react-native-reanimated 中继续循环动画的主要内容,如果未能解决你的问题,请参考以下文章

react-native-reanimated 不起作用

在本机 ios 中找不到模块“react-native-reanimated/plugin”

React-native-reanimated:无法解析“./useValue”

react-native-reanimated 的构建失败

包 react-native-reanimated 找不到

react-native-reanimated iOS 崩溃