欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

React Native 动画(Animated)

程序员文章站 2024-01-14 22:24:52
...

一、前言
对于一个移动应用APP,其中的动画交互能够给用户带来很好的体验,所以动画在移动应用开发过程中是非常重要的;

二、React Native中实现动画的方式

-不断修改state
-Animated API

首先如果不使用任何动画API,那想到的实现动画效果的方式,应该就是通过不断修改state中的组件相关的属性值来实现动画效果,但是这个就是不断的重新渲染整个页面,所以可能会非常影响性能;
React Native中提供了Animated API来实现动画,Animated API可以简洁的实现各种动画和交互方式,并且具备极高的性能;
我们知道所谓动画,无非就是通过平移、缩放、旋转,透明度变换,以及这些基本变换的组合; React Native中也是通过Animated API 来实现对组件透明度style属性(opacity)以及style中transform属性的(translateX,translateY,rotate,scale)的修改来实现平移,缩放,旋转,透明度变换;

三、Animated 动画

-使用Animated 实现动画的步骤

(1)组件需要变化的属性必须使用Animated.Value或者Animated.ValueXY作为值

(2)需要进行动画的组件必须是Animated组件,Animated 提供了
Animated.View,Animated.Image,Animated.Text,Animated.ScrollView, Animated.FlatList, Anmated.SectionList这些基本的动画组件,但是也可以通过Animated.createAnimatedComponent()方法将任意组件变成Animated组件

(3)创建动画
Animated用于创建动画的方法:
Animated.timing():最常用的动画类型,使得值按照过渡曲线随时间变化
Animated.spring():弹簧变化效果
Animated.decay():衰变效果,以一个初始的速度和一个衰减系数逐渐减慢为 0

(4)创建动画之后调用start()方法,stop()方法开启和结束动画
以上就是Animated实现动画的基本步骤

-动画示例
下面我们就按照上面的步骤,来实现透明度,平移,缩放,旋转动画;

透明度动画:

import React from 'react';
import { Animated, Text, View,
Button
} from 'react-native';

export default  class AnimatedViewScreen extends React.Component {
    fadeInOpacity= new Animated.Value(0) //透明度初始值设为0
    componentDidMount() {
        Animated.timing(        //随时间变化而执行动画
            this.fadeInOpacity, //动画中的变量值
            {
                toValue: 1, // 透明度最终变为1,即完全不透明
                duration: 3000, //动画时长
            }
        ).start(); //开始执行动画
    }
    render() {
        return (
            <View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
      <Animated.View style={{width:100,height:100,opacity:this.fadeInOpacity}}>
          <Button title='透明度 按钮'/>
     </Animated.View>  
  </View>
 }
}

平移动画:

import React from 'react';
import { Animated, Text, View,
Button
} from 'react-native';

export default  class AnimatedViewScreen extends React.Component {
    translateX=new Animated.Value(0)
    componentDidMount() {
      Animated.timing(this.translateX,
            {
                toValue:150,
                duration:3000,
            }
        ).start();
    }
    render() {
        return (
            <View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
     <Animated.View style={{width:100,height:100,transform:[{translateX:this.translateX}]}}>
       <Button title='平移按钮'/>
    </Animated.View>
  </View>
 }
}

旋转动画:

import React from 'react';
import { Animated, Text, View,
Button
} from 'react-native';

export default  class AnimatedViewScreen extends React.Component {
    degree=new Animated.Value(0)
    componentDidMount() {
     Animated.timing(this.degree,
            {
                toValue:1,
                duration:3000,
             }
            ).start();
    }
    render() {
       const realDeg=this.degree.interpolate({
        inputRange:[0,1],
        outputRange:['0deg','360deg']
    });
        return (
            <View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
     <Animated.Image style={{width:100,height:100,transform:[{rotate:realDeg}],
                }} source={require('./image/tab_b_select.png')}>
     </Animated.Image>
  </View>
 }
}

这里我们使用了一个interpolate()插值函数,用于将输入值范围转换为输出值范围这里是将[0,1] 输入 转为[‘0deg’,‘360deg’];
interpolate变化过程也可以是多段的输入[0,0.5,1] ,输出为[‘0deg’,‘360deg’,‘0deg’]

缩放动画:

import React from 'react';
import { Animated, Text, View,
Button
} from 'react-native';

export default  class AnimatedViewScreen extends React.Component {
    scale=new Animated.Value(0)
    componentDidMount() {
    Animated.timing(this.scale,
            {
                toValue:1,
                duration:3000,
            }
        ).start();
    }
    render() {
        return (
            <View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
    <Animated.View style={{width:100,height:100,transform:[{scale:this.scale}]}}>
         <Button title='缩放按钮'/>
  </Animated.View>
  </View>
 }
}

-组合动画

上面已经介绍了基本动画,透明度,平移,旋转,缩放,那么复杂的动画就需要这些基本变换的组合,也就是对这些基本动画的组合。

Animated API中提供了以下方法来实现组合动画:

Animated.parallel():参数是动画数组,同时开始动画数组中的全部动画。默认情况下有一个动画停止了,其余的也会停止,可以通过stopTogether选项设置false,来取消这种关联。

Animated.sequence():参数是动画数组,按照顺序执行动画中的所有数组,前一个动画执行完成后,后面一个动画再开始,如果当前动画被中止,则后面的动画不会继续执行;

Animated.stagger():参数是一个延迟时间和一个动画数组,前一个动画开始之后,一段时间后(延迟时间后),后一个动画开始;因为仅仅是前一个动画开始后指定时间,前一个动画并不一定结束了,所以会出现同时执行(重叠)的情况;

组合动画示例:

import React from 'react';
import { Animated, Text, View,
Button
} from 'react-native';

export default  class AnimatedViewScreen extends React.Component {
    sameTimeDegree=new Animated.Value(0)
    sameTimeScale=new Animated.Value(0)
    componentDidMount() {
    
    //释放出来看效果
    // Animated.parallel([
       //     this.createAnimation(this.sameTimeScale,3000),
       //     this.createAnimation(this.sameTimeDegree,3000)
       // ]).start()
       
         //释放出来看效果
        // Animated.sequence([
        //     this.createAnimation(this.sameTimeScale,3000),
        //     this.createAnimation(this.sameTimeDegree,3000)
        // ]).start()

        Animated.stagger(10000,[
            this.createAnimation(this.sameTimeScale,3000),
            this.createAnimation(this.sameTimeDegree,3000)
        ]).start()

    }
    render() {
     const realSameTimeDeg=this.sameTimeDegree.interpolate({
        inputRange:[0,1],
        outputRange:['0deg','360deg']
    })
        return (
            <View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
 <Animated.Image
                 style={{
                     width:100,
                     height:100,
                     transform:[
                         {
                             scale:this.sameTimeScale
                         },
                         {rotate:realSameTimeDeg}
                     ]
                 }}
                 source={require('./image/tab_b_select.png')}
                >
                </Animated.Image>
  </View>
 }
}

-一些注意点
(1)如何使动画循环执行
我们可能需要一个一直旋转的View;
Animated.start()方法可以传入一个参数,这个参数是一个函数,在动画结束时
会回调这个函数,我们可以在这个函数里将属性值重新设置为初始值,然后再启动动画,以此来实现动画的循环执行;

循环动画示例:

import React from 'react';
import {
 Animated, 
 View,
} from 'react-native';
export default  class ProgressBar extends Component{
      deg=new Animated.Value(0)
      rotate=Animated.timing(this.deg, {
             toValue: 1,        //属性目标值
             duration: 1000,    //动画执行时间
             easing: Easing.linear
    })
      componentDidMount() {
        this.startAnimate()
      }
  
      startAnimate(){
        this.deg.setValue(0)
        this.rotate.start(()=>{this.startAnimate()})
    }

   render() {

       const realDeg=this.deg.interpolate({
            inputRange:[0,1],
            outputRange:[0,360]
        });
     return (
     
   <View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
      <Animated.Image style={{width:100,height:100,transform:  [{rotate:realDeg}],
                }} source={require('./image/tab_b_select.png')}>
                
                </Animated.Image>
       <View/>    
    )
   }
}

上面代码就是通过start()启动动画时传入函数,重新调用startAnimation()方法设置属性值为初始值,并重新启动动画实现动画循环执行,从而实现了一个一直旋转的图片这里要注意的是,Animated.timing()方法中easing:Easing.linear属性,也就是设置动画线性匀速播放,否则动画一次播放结束时,进入下一次动画时可能并不是连续的,会有停顿;