您好,登錄后才能下訂單哦!
這篇“怎么使用react native reanimated實現動畫”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“怎么使用react native reanimated實現動畫”文章吧。
首先,從最外層來看,動畫有一個抖動效果:先向左,再向右。可以利用 rotate 旋轉屬性來實現。
其次,中間的文字部分有一個縮放動畫,可以通過 scale 實現。
最后,當文字最小化時,會改變內容,這個需要配合 JS 來實現。
首先通過 useSharedValue
定義一個共享值 rotation
,共享值和 useRef
類似,區別是共享值有一個 value
屬性而不是 current
。
我們使用共享值改變的樣式通過 useAnimatedStyle
包裝一下,再賦值給 Animated.View
,這和使用普通的 React Native 樣式有點區別:
import Animated from 'react-native-reanimated'; const rotation = useSharedValue(0); const shakeStyle = useAnimatedStyle(() => { return { transform: [ { rotateZ: `${rotation.value}deg`, }, ], }; }, []); <Animated.View style={[styles.btn, shakeStyle]}> ... </Animated.View>
每個動畫可以使用 withTiming
更新共享值,并設置動畫的具體參數。它會啟動基于時間的動畫曲線,如執行時間 duration,緩動函數 easing 等。
抖動的過程有三個步驟:向左旋轉,向右旋轉,保持水平。我們使用 withSequence
來編排動畫的順序。
最后,我們使用 withRepeat
讓以上三個步驟無限循環。它接受三個參數:
第一參數是動畫函數;
第二個參數是執行的次數,-1 表示無限次;
第三個參數表示動畫是否反向執行。
注意,在恢復水平后,按鈕仍保持一段時間的靜止,我們可以用到 withDelay
來延遲執行下一個動作。
const SCOPE = 2; useEffect(() => { const turnL = withDelay(1400, withTiming(-SCOPE, { duration: 100, easing: Easing.linear })); // 向左 const turnR = withTiming(SCOPE, { duration: 100, easing: Easing.linear }); // 向右 const holden = withTiming(0, { duration: 100, easing: Easing.linear }); // 水平 const rotateAnimations = withSequence(turnL, turnR, holden); // 編排動畫順序 rotation.value = withRepeat(rotateAnimations, -1); // 重復執行動畫 return () => { cancelAnimation(rotation); }; }, []);
實現縮放動畫的思路與上面基本相似。這里需要注意的是,需要根據實際需求,調整動畫之間的節奏關系。比如縮放開始,抖動開始;縮放結束,抖動也就結束。
const scaleSize = useSharedValue(0.2); const scaleStyle = useAnimatedStyle(() => { return { transform: [ { scale: scaleSize.value, }, ], }; }, []); useEffect(() => { ... const zoomOut = withDelay(1600, withTiming(0.2, { duration: 100, easing: Easing.linear })); const restoreSize = withTiming(1, { duration: 100, easing: Easing.linear }); const scaleAnimations = withSequence(restoreSize, zoomOut); scaleSize.value = withRepeat(scaleAnimations, -1); return () => { ... cancelAnimation(scaleSize); }; }, []) <Animated.View style={[styles.textWrapper, scaleStyle]}> ... <Animated.View>
當我們依賴共享值的變化,需要進一步操作時,可以使用 useAnimatedReaction
,它第一參數中定義依賴的值,第二個參數接受第一個參數的返回值,并進行自定義的操作。
注意,共享值變化不會觸發 JS 線程中的組件更新,改變文案的狀態需要用到 useState
,因為文案改變是在 JS 線程中處理的,可以通過 runOnJS
可以讓函數在 JS 線程中執行。
import { useAnimatedReaction, runOnJS } from 'react-native-reanimation'; ... const [status, setStatus] = useState(true); const scaleSize = useSharedValue(0.2); const toggle = useCallback(() => { setStatus((s) => !s); }, []); useAnimatedReaction( () => { return scaleSize.value; }, (next) => { if (next <= 0.2) { runOnJS(toggle)(); } } ); ... <Text>{status ? '參與話題' : '賺點贊次數'}</Text>
在開發過程中,我們的動畫代碼和狀態代碼都是用 JavaScript 寫在同一個文件中的,你可能會認為你寫的動畫部分的 JavaScript 和狀態部分的 JavaScript 都是運行在同一個線程中的, 但其實并不是這樣的。
React Native 有兩個常用的線程:一個是 React Native 的 JavaScript 線程,另一個是 UI 主線程。
一方面,JavaScript 線程和 UI 主線程是異步通信的,這也意味著,如果是由 JavaScript 線程發起動畫的執行,UI 線程并不能同步地收到該命令并且立刻執行。
另一方面,JavaScript 線程處理的事件很多,包括所有的業務邏輯、React Diff、事件響應等,容易搶占動畫的執行資源。
Reanimated 是如何優化?答案就是:把動畫代碼放到 UI 主線程來執行性能更好、不易卡頓。
它把動畫相關的 JavaScript 函數及其上下文傳給了 UI 主線程。由于 UI 主線程沒有能夠運行 JavaScript 的環境,于是 Reanimated 又創建了一個 JavaScript 虛擬機來運行傳過來的 JavaScript 函數。
在 JavaScript 線程中包括了三個動畫相關的函數或值, useSharedValue
、 useAnimatedStyle
和 useAnimatedGestureHandler
。
這三部分的代碼會在其底層,將相關的回調函數標記為worklet
,被標記的worklet
函數或值會被放在一個由 Reanimated 創建的 JavaScript 虛擬機中執行。而這個由 Reanimated 創建的 JavaScript 虛擬機,會在 UI 線程中執行傳過來的worklet
函數,并且執行的函數還可以同步地操作 UI。
Reanimated 動畫性能好的原因就在于:React Native 的 JavaScript 線程是性能瓶頸點,而在真正執行動畫時,已經把所有與動畫相關 JavaScript 函數都放到了 UI 線程中獨立的 JavaScript 虛擬機中了,并不會和 JavaScript 線程搶占硬件資源。
以上就是關于“怎么使用react native reanimated實現動畫”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。