了解反应本机复活的执行

时间:2018-12-08 21:17:35

标签: react-native expo

我是react-native-reanimated的新手,正努力将其工作原理包裹住。下面的代码在屏幕中间渲染一个方框。在初始渲染时,该框会向右平移4秒钟,然后将其位置重置到屏幕中间。

... imports omitted for brevity

export default class App extends React.Component {
  state = {
    clock: new Clock(),
    translation: new Value(0),
  };

  onPress = () => {
    startClock(this.state.clock);
  };

  getTranslation = (clock, translation) => {
    const state = {
      finished: new Value(0),
      position: translation,
      time: new Value(0),
      frameTime: new Value(0),
    };
    const config = {
      duration: 4000,
      toValue: new Value(300),
      easing: Easing.inOut(Easing.ease),
    };
    return block([
      cond(clockRunning(clock), 0, [
        set(state.finished, 0),
        set(state.position, 0),
        set(state.time, 0),
        set(state.frameTime, 0),
        startClock(clock),
      ]),
      timing(clock, state, config),
      cond(state.finished, set(state.position, 0)),
      state.position,
    ]);
  };

  render() {
    const translation = this.getTranslation(
      this.state.clock,
      this.state.translation
    );
    return (
      <View style={styles.container}>
        <TouchableOpacity onPress={this.onPress}>
          <Animated.View
            style={{
              transform: [
                {
                  translateX: translation,
                },
              ],
              width: 100,
              height: 100,
              backgroundColor: "tomato",
            }}
          />
        </TouchableOpacity>
      </View>
    );
  }
}

我的问题是:

  

1)为什么框仅在初始渲染时平移到右侧?   是什么阻止动画重复?

     

2)onPress处理程序不会重新启动动画。为什么?

1 个答案:

答案 0 :(得分:0)

我也在学习恢复本地化的反应,但是我会尽力回答您的问题。如果有人要编辑答案,请自由编辑。

  
      
  1. 为什么框仅在初始渲染时平移到右侧?是什么阻止动画重复?
  2.   

在安装组件时,translateX的值为0,它将位于屏幕的中心(因为您已经说过,styles.container的样式可能以其子组件为中心)。

并且由于您要从render方法中的getTranslation函数请求转换,因此当组件首次渲染时,将调用getTranslation函数并评估一个节点块:

  1. 执行block列表中的第一个节点,即cond块。它检查时钟是否正在运行。
    • 如果时钟在运行,则什么也不做。
    • 否则,设置timing状态和配置。请记住,state.position设置为0,并且config.toValue也已经设置为300。然后开始计时。
  2. 为计时功能提供了状态及其配置。
    • 它将更新 a 时间范围的位置。在这里,由于您已将state.position设置为0,并将config.toValue设置为300,因此state.position被更新为1(取决于config.duration)。
    • 如果时钟正在运行,它还会在下一帧加入要评估的回调。
  3. 在阻止列表的倒数第二个节点内,它检查状态的finished值是否为1。
    • 动画完成后,或更佳地,当状态position等于配置值toValue时,timing函数将更新finished的值到1。
    • 因此,动画制作完成后,状态的position值将再次设置为0。这意味着该位置会重置为其原始位置。
  4. 在最后一个节点上,状态的position返回到render方法的translation常量进行转换。

    由于时钟开始并且动画尚未结束,因此节点块一次又一次运行。在下一帧中,state.position的值将为2,随后为3,依此类推,直到state.position等于300(config.toValue)。因此,该框将从屏幕的中心移到右侧。但是,如果您将config.toValue设置为-300,则该框将从屏幕的中心移到屏幕的左侧。

    最后,当动画结束时,该块的第3个节点等于true,并且state.position再次为0(在屏幕中央)。

    并且由于您尚未停止时钟(可以使用stopClock(clock)完成),因此检查clockRunning(clock)的第一个节点始终为true。另外,要重复播放动画,您必须在动画完成后重置所有timing状态和配置。

    因此,您必须更改节点块:

            return block([
                cond(
                    clockRunning(clock),
                    [
                        debug('clock is running', clock)
                    ],
                    [
                        debug('clock is NOT running', clock),
                        startClock(clock),
                    ]
                ),
                timing(clock, state, config),
                cond(
                    state.finished,
                    [
                        stopClock(clock),
                        set(state.finished, 0),
                        set(state.position, 0),
                        set(state.time, 0),
                        set(state.frameTime, 0),
                        startClock(clock),
                    ]
                ),
                state.position,
            ]);
    
  
      
  1. onPress处理程序不会重新启动动画。为什么?
  2.   

因为时钟没有停止。也因为状态和配置未重置。因此,要在按下动画时开始动画,可以用许多不同的方法来完成。我将向您展示如何通过一种方式进行操作,这种方式可能会让您对react-native-reanimated以及react-native-gesture-handler有了更多的了解,可以与纯本地动画一起使用,而不必过桥。 / p>

const getTranslation = ({clock, gestureState, translation}) => {
    const state = {
        finished: new Value(0),
        position: translation,
        time: new Value(0),
        frameTime: new Value(0),
    };
    const config = {
        duration: 2000,
        toValue: new Value(150),
        easing: Easing.inOut(Easing.ease),
    };
    return block([
        cond(
            clockRunning(clock),
            [
                debug('clock is running', clock)
            ],
            [
                debug('clock is NOT running', clock),
                set(state.finished, 0),
                set(state.position, 0),
                set(state.time, 0),
                set(state.frameTime, 0),
                startClock(clock),
            ]
        ),
        timing(clock, state, config),
        cond(
            state.finished,
            stopClock(clock)
        ),
        state.position
    ])
};

export default class App extends React.Component {

    gestureState = new Value(-1)

    clock = new Clock()

    translation = cond(
        eq(this.gestureState, State.ACTIVE), // when you start drag, the state will be ACTIVE
        [
            debug('active', this.gestureState, State.ACTIVE),
            getTranslation({clock: this.clock, translation: new Value(0)})
        ],
        [
            debug('not active', this.gestureState, State.ACTIVE)
        ],
    )

    onStateChange = event([
        {
            nativeEvent: {
                state: this.gestureState
            }
        }
    ])

    render() {

        return (
            <View style={styles.container}>
                <PanGestureHandler
                    onGestureChange={this.onStateChange}
                    onHandlerStateChange={this.onStateChange}>
                    <Animated.View style={[
                        styles.box,
                        {
                            transform: [{
                                translateX: this.translation
                            }]
                        }
                    ]}/>
                </PanGestureHandler>
            </View>
        )
    }
}