最近写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]
})
)
};
复制代码
最终三个动画实现文中开头动画。就酱吧~