当前位置: 首页 > 工具软件 > React Motion > 使用案例 >

React Native 动画(Animated)

郭璞
2023-12-01

一、前言
对于一个移动应用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:['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/>    
    )
   }
}

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

(2)创建动画组件

上面提到了除了Animated提供的支持的一些动画组件之外,我们可以使用Animated.createAnimatedComponent()方法来将任意组件变成动画组件;但是在实际尝试的过程中将Button变成动画组件好像无效,其他的组件都是有效的;

下面给出将TextInput变成动画组件,并进行动画的实例:

import React from 'react';
import {
    View,
    TextInput
} from 'react-native';
const AnimatedTextInput=Animated.createAnimatedComponent(TextInput);
export default class MainScreen extends React.Component{
    scale=new Animated.Value(0);
     componentDidMount() {
        Animated.timing(  //随时间变化而执行动画
            this.scale,   //动画中的变量值
            {
                toValue: 1,  //透明度最终变为1,即完全不透明
                duration: 3000,
            }
        ).start();
   }
   render(){
     return (
            <View>
               <AnimatedTextInput style={{width:100,height:200,
                    transform:[{scale:this.scale}],
                    backgroundColor:'red'
                }} height={200}>
                    请输入内容
                </AnimatedTextInput>
            </View>
      )
   }
}

以上就是React Native 中Animated动画的基本使用

 类似资料: