最近寫rn項目遇到動畫需求,分享下代碼供有需求的前端er參考~
先上最終效果圖,以下css
第一步:獲取動畫起點位置,首先點擊時獲取動畫開始位置,利用mesure方法獲取元素距離屏幕左上角位置;前端
task-list.js文件react
方法參數:task-此條任務信息,object;mount-可領取金幣數額 numberspring
doneCallBack=(task, mount)=>{
let refname = `goldimg${task.task_id}`;
let X,Y;
this.refs[refname].measure((frameX, frameY, frameWidth, frameHeight, pageX, pageY)=>{
X=pageX;
Y=pageY;
this.props._showAnimate(true, pageX, pageY, mount);
});
};
複製代碼
第二步:task-list.js父組件main.js中執行三部分動畫;數組
1 清除上一次動畫定時器,並不可見動畫;
2 存儲位置信息,將金幣 如60,拆分紅[6, 0],以建立數字滾動動畫;
3 執行金幣動畫,金幣背景動畫,數字動畫
bash
方法參數:status- boolean 是否須要執行動畫;X-number 距離屏幕左側距離;Y-number 距離屏幕頂部距離;mount-number 可領取金幣數額;函數
_showAnimate=(status, X, Y ,mount)=>{
this.timer && clearTimeout(this.timer);
this.state.isShowAnim && this.setState({isShowAnim:false}); //上兩行防止屢次點擊出現混亂
this.setState({
clickedPositionX:X,
clickedPositionY:Y,
mount:mount.toString().split(''),
isShowAnim:true,
}, ()=> {
if(status){
this.goldAnimate._startGoldAnimate();// 執行金幣動畫
this.goldBgAnimate._startGoldAnimate(); // 執行金幣背景動畫
this.goldnumRunAnimate._startAnimate(); // 執行數字滾動動畫
this._getTaskList(); // 從新獲取任務數據
}
});
// 4s後去掉領取獎勵動畫彈窗
this.timer = setTimeout(()=>{
this.setState({
isShowAnim:false
})
}, 4000)
};
複製代碼
上金幣動畫代碼:gold-animate.js動畫
使用rn內置Animated模塊,
三種動畫效果
1 spring - 彈簧物理模型,
2 timing - easing函數(大多數狀況下使用);
3 decay - 指定的初始速度開始,而後速度變慢至停下;
動畫先向上(x)彈40,而後向右下(x,y)同時移動
translateYVal是new Animated.Value(0)動畫初始值,爲0;
useNativeDriver:true 使用原生驅動加載動畫,能夠提升動畫流暢,可是對css動畫部分支持;
interpolate插值函數,具體參考官方文檔;
clickedPositionX 點擊發生時距離屏幕左側;
finalPosY 金幣背景的Y位置
ui
js部分this
_startGoldAnimate=()=>{
let spring = Animated.spring, timing = Animated.timing, parallel = Animated.parallel;
spring(
this.state.translateYVal,
{
toValue:1,
duration:500,
friction:3,
tension:50,
useNativeDriver:true
}
).start();
parallel([
timing(
this.state.translateXVal,
{
toValue:1,
duration:300,
useNativeDriver:true,
delay:600
}
),
timing(
this.state.translateSecYVal,
{
toValue:1,
duration:300,
useNativeDriver:true,
delay:600
}
)
]).start();
};
複製代碼
react部分
return (
<Animated.View
style={{
position:'absolute',
zIndex:10000,
height:'100%',
width:'100%',
left:clickedPositionX - 5,
top:clickedPositionY - 5,
transform:[
{
translateY:translateYVal.interpolate({
inputRange: [0, 0.7, 1],
outputRange: [0, -40, 0]
})
},
]
}}
>
<Animated.Image
style={{
height:22,
width:22,
transform:[
{
translateX:translateXVal.interpolate({
inputRange: [0, 1],
outputRange: [0, Utils.windowSize.width - clickedPositionX - 89]
})
},
{ translateY:translateSecYVal.interpolate({
inputRange: [0, 1],
outputRange: [0, finalPosY - clickedPositionY + 15 ]
})
},
],
}}
source={require('resource/newtask/animategold.png')}
>
</Animated.Image>
</Animated.View>
)
複製代碼
代碼繼續,按順序金幣背景動畫
gold-bg-animate.js
動畫部分:背景向上Y,移動60
_startGoldAnimate = () => {
Animated.timing(
this.state.animValue,
{
toValue:1,
duration:1000,
useNativeDriver:true
}
).start();
}
複製代碼
react部分
return (
<View
ref={(view) => this.goldNumBg = view}
style={styles.container}
>
<Animated.Image
style={{
position:'absolute',
bottom:-60,
right:0,
height:55,
width:104,
transform:[
{
translateY:animValue.interpolate({
inputRange: [0, 1],
outputRange: [0,-60]
})
}
],
}}
source={require('resource/newtask/animate_gold_bg.png')}
>
</Animated.Image>
</View>
)
複製代碼
接下來最後一個動畫,數字滾動動畫
文件goldnum-run-animate.js
動畫部分,第一個透明度從0到1;每一個數字依次開始動畫,注意裏面的delay屬性;
_startAnimate = () => {
Animated.timing(
this.state.opacityAnim,
{
toValue:1,
duration:1000,
}
).start();
this.state.animAry.forEach((item, index) => {
Animated.timing(
item.value,
{
toValue:1,
duration:(Number(item.num)+1) * 200,
delay:index * 400
}
).start();
});
};
複製代碼
animAry爲建立出數組,爲每一個數字添加動畫初始值;
let numAry = this.state.mount;
let animAry = [];
for (let i = 0; i < numAry.length; i++) {
animAry.push({
num: numAry[i],
name: `animValue${i}`,
value: new Animated.Value(0),
})
}
複製代碼
react部分:mount就是上文提到過的數字改造的數組,60=》[6, 0]
return (
<View style={styles.numContainer}>
<Animated.Text
style={[
styles.goldText,
styles.addMark,
{
opacity:opacityAnim.interpolate({
inputRange:[0, 1],
outputRange:[0, 1]
})
}
]}
>
+
</Animated.Text>
{
mount.map((item,index) => {
return (
<Animated.View
key={index}
style={[styles.textcon,{
height:(Number(item)+1) * 30,
top:this.createAnimate(item, index)
}]}>
{
this._createSingleNum(item)
}
</Animated.View>
)
})
}
</View>
)
複製代碼
_createSingleNum(item)方法以下:
參數 item-傳入的數字,number;
_createSingleNum = (num) => {
let ary =[];
for (let i =0; i <= num; i++) {
ary.push(i)
}
return (
<View>
{
ary.map((item,index)=>{
return (<Text key={index} style={[styles.goldText]}>{item}</Text>)
})
}
</View>
)
};
複製代碼
建立的結果以下,每一個數字列有個動畫,從0-5滾動;
<View>
<Text>0<Text>
<Text>1<Text>
<Text>2<Text>
<Text>3<Text>
<Text>4<Text>
<Text>5<Text>
<View>
複製代碼
createAnimate()方法,
參數:it-數字,number 例如:5 ind-索引值,number,如 0;
爲數組中每一個數字,建立動畫,最終經過top值改變行程動畫
createAnimate = (it, ind) => {
let propName = `animValue${ind}`;
return (
this.state.animAry[ind].value.interpolate({
inputRange: [0, 1],
outputRange: [30,-30 * it]
})
)
};
複製代碼
最終三個動畫實現文中開頭動畫。就醬吧~