React Native 布林值動畫
2018年5月6日3 分鐘閱讀

React Native 布林值動畫

這篇文章是通過 AI 翻譯生成,可能有不準確之處。

React Native 中的動畫

Animated API 是 React Native 中創建引人入勝動畫的絕佳方法。

它通過建立一個動畫數值補間,然後將動畫數值映射到您想要動畫化的樣式上來工作。如果您對 Animated 不熟悉,請查看文檔

用布林值控制動畫?

有時,我們想要使用布林值來為組件製作動畫,但 Animated API 預設並不提供此功能。這有點不方便。例如,您想要在按鈕上實現淡入、淡出效果。實現可能如下所示:

Container(之前)

// ...

class MyContainer extends React.Component {
  // ...
  toggleBtn() {
    if (this.state.btnActive) {
      this.setState({ btnActive: false })
      Animated.spring(this.state.animatedValue, {
        duration: 300,
        toValue: 0,
        friction: 10,
      }).start()
    } else {
      this.setState({ btnActive: true })
      Animated.spring(this.state.animatedValue, {
        duration: 300,
        toValue: 1,
        friction: 10,
      }).start()
    }
  }
  render() {
    return (
      // ...
      <Animated.View
        style={{
          opacity: this.state.animateValue.interpolate({
            inputRange: [0, 1],
            outputRange: [0, 1],
          }),
        }}
      >
        <Button title="I am a button" />
      </Animated.View>
      // ...
    )
  }
}

這並不理想,原因有兩個:

  1. 要切換按鈕需要執行兩個任務
  2. 動畫實現細節在 Container 檔案中

動畫高階組件

創建一個 animatedHOC 可以解決這個問題。額外的層級可以抽象化切換按鈕動畫的細節,這樣 Container 就不再需要關心按鈕應該如何動畫化。

animatedHOC 處理所有動畫數值補間邏輯如下:

import React, { Component } from 'react';
import {
  Animated,
  InteractionManager
} from 'react-native';

export default function animatedHOC(WrappedComponent) {
  return class AnimatedCtrl extends Component {
    constructor(props) {
      super(props);
      this.state = {
        active: props.active,
        animateValue: new Animated.Value(0)
      };
    }
    componentWillReceiveProps(nextProps) {
      if (this.state.active === nextProps.active) return;
      Animated.spring(
        this.state.animateValue,
        {
          duration: this.props.duration,
          // 被 HOC 包裝的組件可以根據 0 到 1 之間的
          // animateValue 來決定要實現什麼動畫。
          toValue: nextProps.active ? 1 : 0,
          friction: 10
        }
      ).start();
      this.setState({
        active: nextProps.active
      });
   }
   render() {
     return (<WrappedComponent
       { ...this.props }
       animateValue={ this.state.animateValue }
     />);
  }
};

FadeAnimationBtn 接收 animateValue 屬性來實現相應的動畫。

Container(之後)

import React from 'react'
import { View, Animated, Button, Text } from 'react-native'
import Button from 'path/to/myButton'
import animatedHOC from '../animatedHOC'

export const FloatBtn = ({ onPress, title, animateValue }) => (
  <Animated.View
    style={{
      opacity: animateValue.interpolate({
        inputRange: [0, 1],
        outputRange: [0, 1],
      }),
    }}
  >
    <Button onPress={onPress} title={title} />
  </Animated.View>
)

export default animatedHOC(FloatBtn)

注意 FadeAnimationBtn 必須被 animatedHOC 包裝,因為 FadeAnimationBtn 需要 animatedValue 作為其屬性。

Container

// ...
import FadeAnimationBtn from 'path/to/FadeAnimationBtn';

class MyContainer extends React.Component {
  // ...
  toggleBtn() {
    this.setState({
      btnActive: !this.state.btnActive
    });
  }
  render() {
    return (
      // ...
      <FadeAnimationBtn
        active={ this.state.btnActive }
        title="I am a Button"
      >
      // ...
    );
  }
}

通過這種方法,我們可以更簡潔地實現布林值動畫。Container 只需要關心按鈕的狀態。

以上只是最基本的實現。您可以通過添加 InteractionManager 或任何您想要的功能來增強 AnimatedHOC。您還可以根據 animatedValue 添加其他過渡效果。

結論

高階組件是一個強大的概念,通過將重複的部分和關注點分離到組件中,使我們的程式碼更簡潔和可維護。希望這篇文章對您有所幫助,謝謝!