天天看點

19.React Native動畫效果操作集合四1.插值動畫2.動畫組合3.動畫循環4.跟蹤動态值5.跟蹤手勢6.響應目前的動畫值

目錄

1.插值動畫

1.1插值動畫

1.2使用過程

2.動畫組合

2.1Animated.parallel()并行啟動動畫

2.2Animated.sequence()按順序啟動動畫

3.動畫循環

4.跟蹤動态值

5.跟蹤手勢

5.1Scroll滾動

6.響應目前的動畫值

1.插值動畫

1.1插值動畫

每個屬性都可以首先通過插值運作。插值将輸入範圍映射到輸出範圍,通常使用線性插值,但也支援放寬(easing)功能。預設情況下,它會将曲線外推到給定範圍之外,但您也可以讓它鉗制輸出值-指定輸出值範圍。

插值示例:

簡單的示例将輸入值[0,1]範圍映射[0,100]輸出範圍;

value.interpolate({
  inputRange: [0, 1],
  outputRange: [0, 100]
});
           

例如,您可能希望考慮将動畫Animated.Value()從0變為1,但将位置從150px變為0px,不透明度從0變為1。通過像這樣修改上面示例中的樣式,可以很容易地做到這一點;

style={{
    opacity: this.state.fadeAnim, //需要綁定插值的指定fadeAnim屬性
    transform: [{
      translateY: this.state.fadeAnim.interpolate({    
        inputRange: [0, 1],    //設定輸入的範圍
        outputRange: [150, 0]  // 0 : 150, 0.5 : 75, 1 : 0    //設定實際映射的輸出範圍
      }),
    }],
  }}
           

interpolate()還支援到字元串的映射,進而可以實作顔色以及帶有機關的值的動畫變換。例如你可以像下面這樣實作一個旋轉動畫;

value.interpolate({
  inputRange: [0, 360],
  outputRange: ["0deg", "360deg"]
});
           

interpolate()

還支援任意的漸變函數,其中有很多已經在

Easing

類中定義了,包括二次、指數、貝塞爾等曲線以及 step、bounce 等方法。

interpolation

還支援限制輸出區間

outputRange

。你可以通過設定

extrapolate

extrapolateLeft

extrapolateRight

屬性來限制輸出區間。預設值是

extend

(允許超出),不過你可以使用

clamp

選項來阻止輸出值超過

outputRange

1.2使用過程

a.初始化動畫值

this.animation = new Animated.Value(this.props.progress);

b.綁定動畫值到指定插值範圍(示例動态調整寬度)

//插入動畫值(設定animation數值範圍)
        //每個屬性都可以首先通過插值運作。插值将輸入範圍映射到輸出範圍,
        // 通常使用線性插值,但也支援放寬功能。預設情況下,它會将曲線外推到給定範圍之外,
        // 但您也可以讓它鉗制輸出值。
        /**
         * 一個簡單的例子0-1映射為0-100範圍:
         * value.interpolate({
              inputRange: [0, 1],
              outputRange: [0, 100]
            });

         extrapolate:使用clamp選項來阻止輸出值超過outputRange
         */
        const widthInterpolated = this.animation.interpolate({
            inputRange:[0, 1],
            outputRange:['0%', '100%'],
            extrapolate:'clamp'
        });
           

c.綁定插值給指定屬性

width:widthInterpolated,

<Animated.View
                        style={{
                            position:"absolute",
                            left:0,
                            top:0,
                            bottom:0,
                            width:widthInterpolated,
                            backgroundColor:barColor,
                            borderRadius
                        }}
           

d.具體實作相容IOS和Android插值進度條效果參看:

https://blog.csdn.net/ahou2468/article/details/93720144

2.動畫組合

動畫還可以使用組合函數以複雜的方式進行組合:

a.Animated.delay()在給定延遲後開始動畫。

b.Animated.parallel()同時啟動多個動畫。

c.Animated.sequence()按順序啟動動畫,等待每一個動畫完成後再開始下一個動畫。

d.Animated.stagger()按照給定的延時間隔,順序并行的啟動動畫。

2.1Animated.parallel()并行啟動動畫

同時開始一個動畫數組裡的全部動畫。預設情況下,如果有任何一個動畫停止了,其餘的也會被停止。你可以通過

stopTogether

選項來改變這個效果。

class FadeView extends React.Component{
    state = {
        bounceValue: new Animated.Value(0),    //定義縮放動畫值
        rotateValue: new Animated.Value(0)     //定義旋轉動畫值
    };


    componentDidMount() {
    }

    executionAnimated(){
        Animated.parallel([//并行執行動畫
            Animated.spring(this.state.bounceValue, {//彈簧效果執行動畫
                toValue:1,
                duration:3000,
            }),
            Animated.timing(this.state.rotateValue,{//線性執行動畫
                toValue:1,
                duration:3000,
                easing:Easing.elastic(1)
            })
        ]).start();
    }

    render(){
        //使用專門的可動畫化的View元件
        return (<Animated.View
            style={{
                ...this.props.style,
                transform:[
                    {scale:this.state.bounceValue}, //綁定縮放值
                    {rotate:this.state.rotateValue.interpolate({//插入動畫
                            //綁定輸入值映射對應的旋轉度數值
                            inputRange:[0,1],
                            outputRange:['0deg', '180deg']
                        })}
                ]
            }}>
            {this.props.children}
        </Animated.View>);
    }
}
           

2.2Animated.sequence()按順序啟動動畫

Animated.sequence([//順序執行動畫
            Animated.spring(this.state.bounceValue, {//第一個執行
                toValue:1,
                duration:3000,
            }),
            Animated.timing(this.state.rotateValue,{//第二個執行
                toValue:1,
                duration:3000,
                easing:Easing.elastic(1)
            })
        ]).start();//啟動動畫
           

3.動畫循環

Animated的start方法可以接受一個回調函數,在動畫或某個流程結束的時候執行,通過該方法監聽動畫的結束在回調函數中再次執行上例中的_onPress即可重複執行動畫:

實作如下循環動畫效果

Animated.sequence([//順序執行動畫
            Animated.spring(this.state.bounceValue, {//第一個執行
                toValue:1,
                duration:3000,
            }),
            Animated.timing(this.state.rotateValue,{//第二個執行
                toValue:1,
                duration:3000,
                easing:Easing.elastic(1)
            })
        ]).start(() => this._onPress());//啟動動畫,循環調用_onPress()

style={{
            ...this.props.style,
            transform:[
                {scale:this.state.bounceValue}, //縮放
                {rotate:this.state.rotateValue.interpolate({
                        inputRange:[0,1],
                        outputRange:['0deg', '180deg']
                    })}
            ]
        }}
           

4.跟蹤動态值

動畫中所設的值還可以通過跟蹤别的值得到。你隻要把 toValue 設定成另一個動态值而不是一個普通數字就行了。比如我們可以用彈跳動畫來實作聊天頭像的閃動,又比如通過timing設定duration:0來實作快速的跟随。他們還可以使用插值來進行組合:

Animated.spring(follower, { toValue: leader }).start();
Animated.timing(opacity, {
  toValue: pan.x.interpolate({
    inputRange: [0, 300],
    outputRange: [1, 0]
  })
}).start();
           

leader和follower動畫值可以通過Animated.ValueXY()實作. 是一個友善的處理 2D 互動的辦法,譬如旋轉或拖拽。它是一個簡單的包含了兩個Animated.Value執行個體的包裝,然後提供了一系列輔助函數,使得ValueXY在許多時候可以替代Value來使用。比如在上面的代碼片段中,leader和follower可以同時為valueXY類型,這樣 x 和 y 的值都會被跟蹤。

5.跟蹤手勢

Animated.event是 Animated 中與輸入有關的部分,允許手勢或其它事件直接綁定到動态值上。它通過一個結構化的映射文法來完成,使得複雜事件對象中的值可以被正确的解開。第一層是一個數組,允許同時映射多個值,然後數組的每一個元素是一個嵌套的對象。在下面的例子裡,你可以發現scrollX被映射到了event.nativeEvent.contentOffset.x(event通常是回調函數的第一個參數),并且pan.x和pan.y分别映射到gestureState.dx和gestureState.dy(gestureState是傳遞給PanResponder回調函數的第二個參數)

例如,在使用水準滾動手勢時,可以執行以下操作,以便将event.nativeevent.contentoffset.x映射到scrollx(animated.value):

onScroll={Animated.event(
   // scrollX = e.nativeEvent.contentOffset.x
   [{ nativeEvent: {
        contentOffset: {
          x: scrollX
        }
      }
    }]
 )}
           

在Pan手勢中:

把手勢狀态的gestureState.dx和gestureState.dy的值指派到pan.x何pan.y變量中(gestureState通常為PanResponder回調方法中的第二個參數):

onPanResponderMove={Animated.event(
  [null, // ignore the native event
  // extract dx and dy from gestureState
  // like 'pan.x = gestureState.dx, pan.y = gestureState.dy'
  {dx: pan.x, dy: pan.y}
])}
           

5.1Scroll滾動

首先,我們建立一個animated.value,它是一個簡單的值,可以使用animated api設定動畫。

然後我們将動畫值綁定到滾動視圖滾動位置。為了做到這一點,我們使用了一個animated.event,它映射到我們想要綁定到動畫值的事件對象屬性。在這種情況下,它是<eventobject>.nativeevent.contentoffset.y。

然後我們使用動畫值的插值方法将滾動位置映射到所需的标題高度。我們需要的是,當滾動位置為0時,頭部的高度,當滾動位置移動到HEADER_MAX_HEIGHT和HEADER_MIN_HEIGHT之間的差時,頭部處于HEADER_MIN_HEIGHT高度。

最後,我們隻需将标題視圖的高度設定為動畫值。我們還将ScrollEventThrottle屬性設定為16,這樣事件的發送頻率就足夠平滑動畫了。

此時,标題将随滾動位置移動,使用相同的技術,我們可以在使用者滾動時在标題中顯示幾乎所有我們想要的内容。是時候發揮你的創造力了:)

為此,我們将animated.event與scrollview onscroll屬性一起使用。

...

constructor(props) {
  super(props);

  this.state = {
    scrollY: new Animated.Value(0),
  };
}

...
  
render() {
  const headerHeight = this.state.scrollY.interpolate({
    inputRange: [0, HEADER_SCROLL_DISTANCE],
    outputRange: [HEADER_MAX_HEIGHT, HEADER_MIN_HEIGHT],
    extrapolate: 'clamp',
  });
  
  ...

  <ScrollView
    style={styles.fill}
    scrollEventThrottle={16}
    onScroll={Animated.event(
      [{nativeEvent: {contentOffset: {y: this.state.scrollY}}}]
    )}
  >
    ...
  </ScrollView>
  <Animated.View style={[styles.header, {height: headerHeight}]}>
    ...
  </Animated.View>
  ...
}
           

6.響應目前的動畫值

你可能會注意到這裡沒有一個明顯的方法來在動畫的過程中讀取目前的值——這是出于優化的角度考慮,有些值隻有在原生代碼運作階段中才知道。如果你需要在 JavaScript 中響應目前的值,有兩種可能的辦法:

a.spring.stopAnimation(callback)會停止動畫并且把最終的值作為參數傳遞給回調函數callback——這在處理手勢動畫的時候非常有用。

spring.addListener(callback)會在動畫的執行過程中持續異步調用callback回調函數,提供一個最近的值作為參數。這在用于觸發b.狀态切換的時候非常有用,譬如當使用者拖拽一個東西靠近的時候彈出一個新的氣泡選項。不過這個狀态切換可能并不會十分靈敏,因為它不像許多連續手勢操作(如旋轉)那樣在 60fps 下運作。

監聽AnimatedValueXY類型translateValue的值變化:

this.state.translateValue.addListener((value) => {   
    console.log("translateValue=>x:" + value.x + " y:" + value.y);
});
this.state.translateValue.stopAnimation((value) => {   
    console.log("translateValue=>x:" + value.x + " y:" + value.y);
});
           

監聽AnimatedValue類型translateValue的值變化:

this.state.translateValue.addListener((state) => {   
    console.log("rotateValue=>" + state.value);
});
this.state.translateValue.stopAnimation((state) => {   
    console.log("rotateValue=>" + state.value);
});
           

參考:

react native學習筆記29——動畫篇 Animated進階動畫

https://www.2cto.com/kf/201803/731179.html

動畫

https://reactnative.cn/docs/animations/#animated-api

ScrollView

https://blog.csdn.net/u011733020/article/details/76945254

繼續閱讀