1. 程式人生 > >React-Native專案中使用動畫-Animated

React-Native專案中使用動畫-Animated

動畫 Animated

RN中的動畫在某種程度上可以理解為“屬性動畫”,也就是以某種過渡方式改變元件樣式屬性值(如元件樣式的left值),驅動元件以動畫的形式發生變化(位移、形變或轉動)

可動畫化的元件:

  • View (Animated.View)
  • Text (Animated.Text)
  • Image (Animated.Image)
  • 使用createAnimatedComponent自定義

三種動畫型別:

  • spring 基礎的單次彈跳物理模型
  • decay 以一個初始速度開始並且按一定的衰減比逐漸減慢直至停止
  • timing 時間和變數線性變化

1.關聯屬性的初始化

關聯屬性指的是動畫過程中對應變化的屬性,這個屬性的型別是Animated.Value

,可以通過new Animated.Value()new Animated.ValueXY()(處理2D動畫)等方法初始化,如下:

class PlaygroundContainer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            left1: new Animated.Value(0),
            rotation2: new Animated.Value(0),
            pan: new Animated.Value
({x:0, y:0}) } } ... }

2.與元件關聯

用spring實現的動畫

import loadingImage from '../../assets/0.gif'
...
class PlaygroundContainer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            left1: new Animated.Value(0),
        }
    }
    componentDidMount() {
        Animated
.spring(this.state.left1, { toValue: 100, //屬性目標值 friction: 1, //摩擦力 (越小 振幅越大) tension: 100, //拉力 }).start(); //執行動畫 } render(){ return ( ... <Animated.Image style={[styles.image,{left: this.state.left1}]} source={ loadingImage }/> ... ) } }

用timing實現的翻轉動畫效果

import loadingImage from '../../assets/0.gif'
...
class PlaygroundContainer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            rotation2: new Animated.Value(0),
        }
    }
    componentDidMount() {
        Animated.timing(this.state.rotation2, {
            toValue: 1,        //屬性目標值
            duration: 3000    //動畫執行時間
        }).start();    //執行動畫
    }
    render(){
        return (
            ...
            <Animated.Image
                style={[styles.image,{
                    transform:[
                        {
                            rotateX: this.state.rotation2.interpolate({
                                inputRange:[0,1],
                                outputRange:['0deg','360deg']
                            })
                        }
                    ]
                }]}
                source={ loadingImage }/>
            ...
        )
    }
}

這裡用到<l style="color:red">插值函式</l>interpolate,它可以接受一個輸入區間,然後將其對映到另一個的輸出區間,如下:

{
    rotateX: this.state.rotation2.interpolate({
        inputRange:[0,1],
        outputRange:['0deg','360deg']
    })
}

通過對映,

rotation2的value 對映輸出
0
0.2 72°
0.5 180°
1 360°

用decay實現衰減動畫

import loadingImage from '../../assets/0.gif'
...
class PlaygroundContainer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            decayLeft4: new Animated.Value(0),
        }
    }
    componentDidMount() {
        Animated.decay(this.state.decayLeft4, {
            velocity: 2,// 起始速度,必填引數。
            deceleration:0.992     //速度衰減比例,預設為0.997。
        }).start();
    }
    render(){
        return (
            ...
            <Animated.Image
                style={[styles.image,{
                    left: this.state.decayLeft4
                }]}
                source={ loadingImage }/>
            ...
        )
    }
}

組合畫效果

  • static sequence(animations: Array<CompositeAnimation>) (接受一個動畫陣列,<b style="color: red">依次</b>執行數組裡的動畫)
  • static parallel(animations: Array<CompositeAnimation>, config?: ParallelConfig) (接受一個動畫陣列,<b style="color: red">同時</b>執行數組裡的動畫)

      import loadingImage from '../../assets/0.gif'
      ...
      class PlaygroundContainer extends Component {
          constructor(props) {
              super(props);
              this.state = {
                  left3: new Animated.Value(0),
                  rotation3: new Animated.Value(0),
                  scale3: new Animated.Value(0.5),                }
          }
          componentDidMount() {
              //序列執行
              Animated.sequence([    
                  // 並行執行(滾動,同時旋轉)
                  Animated.parallel([
                      Animated.timing(this.state.left3, {
                          toValue: 1,
                          duration: 3000,
                      }),
                      Animated.timing(this.state.rotation3, {
                          toValue: 1,
                          duration: 1000,
                      }),
                  ]),
                  // 滾動、旋轉結束  執行縮放
                  Animated.timing(this.state.scale3, {
                      toValue: 1,
                      duration: 500,
                  })
              ]).start()    //執行動畫
          }
          render(){
              return (
                  ...
                  <Animated.Image
                      style={[styles.image,{
                          left: this.state.left3.interpolate({
                              inputRange:[0,1],
                              outputRange:[0, width - 100]
                          }),
                          transform:[
                              {rotateZ: this.state.rotation3.interpolate({
                                      inputRange:[0,1],
                                      outputRange:['0deg','360deg']})
                              },
                              {rotateX: this.state.rotation3.interpolate({
                                      inputRange:[0,1],
                                      outputRange:['0deg','360deg']})
                              },
                              {scale: this.state.scale3}
                          ]
                      }]}
                      source={ loadingImage }/>
                  ...
              )
          }
      }

用delay做延時動畫

Animated.delay(1000)延時1000ms
delay動畫放進sequence 執行序列的動畫陣列中

import loadingImage from '../../assets/0.gif'
...
class PlaygroundContainer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            left5: new Animated.Value(0),
        }
    }
    componentDidMount() {
        Animated.sequence([
            // 1000 ms後執行
            Animated.delay(1000),
            Animated.timing(this.state.left5, {
                toValue: 100,// 起始速度,必填引數。
                duration: 1000
            })
        ]).start()
    }
    render(){
        return (
            ...
            <Animated.Image
                style={[styles.image,{
                    left: this.state.left5
                }]}
                source={ loadingImage }/>
            ...
        )
    }
}