使用 RN Animated 做一個“新增購物車”動畫
最近在選座的新專案中試用了一下 React Native,熟悉新框架的同時,可以略微將互動效果和 Native 看齊了。
分享一下專案本身比較重要的一個互動動畫的做法, RT。
這次我們就不裝大象了,因為我真的買了冰箱 =,=
本著言簡意賅,不故弄玄虛的原則,依然是三步:
第 1 步:通過 Animated
建立合成動畫的 View。仔細觀察,“選擇座位” 動畫和 “新增購物車” 動畫類似,都可以分解為透明度變化( opacity
)和 3D 變化( transform
)兩部分。而 transform
又能進一步分解為水平位移( translateX
)、垂直位移( translateY
)、旋轉( rotateZ
)、縮放( scale
)四個分動畫( 程式碼見 render()
);
第 2 步:響應點選事件,準備好動畫的相關引數。目標位置被點選時,在動畫的父級元件中通過 onPress
事件的 event
物件獲取點選的位置座標( event.nativeEvent.changedTouches[0].pageX|Y
)作為動畫起始位置。終點位置一般為固定位置,當然你也可以指定動態值;
第 3 步:獲取引數, start()
播放動畫( 程式碼見 componentDidMount()
)。從父級元件中獲取位置引數並通過 props
傳入子動畫元件。其中 opacity
、 rotateZ
、 scale
屬性值都是靜態變化,分別為 1 -> 0
0deg -> 360deg
1 -> 0
(可以利用 interpolate
方法做各個屬性不同型別值的 mapping,更加方便統一控制);
注意:類似的全域性動畫要展示在最高層級,防止被後渲染的元件遮擋,最好單獨封裝組建提升其在 UI 中的渲染層級。
import React from 'react'; import { StyleSheet, View, Image, Animated } from 'react-native'; export default class SeatDroppingextends React.PureComponent{ constructor (props) { super(props); this.state = { animValue: new Animated.Value(0), fromPageX: props.clickedPosition.x, // from event.nativeEvent.changedTouches[0] fromPageY: props.clickedPosition.y, toPageX: props.psgPosition.x, toPageY: props.psgPosition.y }; } componentDidMount() { Animated.timing( this.state.animValue, { toValue: 1, duration: 600 } ).start(); } render () { const { animValue, fromPageX, fromPageY, toPageX, toPageY } = this.state; return ( <Animated.View style={{ zIndex: 9, position: 'absolute', opacity: animValue.interpolate({ inputRange: [0, 1], outputRange: [1, 0] }), transform: [ { translateX: animValue.interpolate({ inputRange: [0, 1], outputRange: [`${fromPageX}px`, `${toPageX}px`] }) }, { translateY: animValue.interpolate({ inputRange: [0, 1], outputRange: [`${fromPageY}px`, `${toPageY}px`] }) }, { rotateZ: animValue.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '180deg'] }) }, { scale: animValue.interpolate({ inputRange: [0, 1], outputRange: [1, 0] }) } ]}} > <Image source={require('../img/ic_seat_focus.png')} style={[ { width: 36, height: 32, zIndex: 9 } ]} /> </Animated.View> ); } }
Done~