React Native Animated动画

来源:互联网 发布:java org.apache.http 编辑:程序博客网 时间:2024/06/07 02:40

在React Native中,我们可以通过两种方式实现一个动画效果:

  • LayoutAnimation
  • Animated

关于LayoutAnimation,我之前写过一篇学习博客(React Native LayoutAnimation动画)。此主要用于在页面布局改变的时候添加一些动画效果,但如果想要实现一些更精细,复杂的动画,LayoutAnimation就会比较困难,所以React Native还为我们提供了Animated组件,用来实现一些复杂的动画效果。

一、单个动画

Animated为我们提供了三种类型的动画:spring,timing,decay。

1、Spring 弹跳效果动画

  • friction 摩擦系数,默认40
  • tension 张力系数,默认7
  • bounciness
  • speed

Spring支持 friction与tension 或者 bounciness与speed 两种组合模式,这两种模式不能并存。 其中friction与tension模型来源于origami,一款F家自制的动画原型设计工具,而bounciness与speed则是传统的弹簧模型参数。

2、timing 带有时间的渐变动画

  • duration 动画运行时间
  • easing 动画曲线函数,可以从Easing模块中获取更多预定义的函数
  • delay: 动画执行延迟时间(单位:毫秒).默认为0ms

3、decay 带有加速度值的动画,类似于正弦值

  • velocity:初始速度,必须要填写
  • deceleration:速度减小的比例,加速度。默认为0.997

4、另外,现在RN只为我们提供Animated.View,Animated.Image,Animated.Text三种动画组件,但是可以通过Animated.createAnimatedComponent(component)创建动画组件。

有了上面的知识,我们就可以简单实现一个淡入的动画效果:
这里写图片描述

具体实现步骤如下:

1、引入Animated组件

import {    StyleSheet,    Animated,//要实现Animated 动画,首先要引入Animated组件    Easing,    View,    Image,    Text,}from 'react-native';

2、 在构造方法中初始化一个Animated对象

// 构造    constructor(props) {        super(props);        // 初始状态        this.state = {            anim: new Animated.Value(0),//初始化一个动画对象        };    }

3、添加动画组件,并将要改变的动画组件样式属性值设为动画对象

render() {        return (            <View style={styles.container}>                <Animated.Image source={require('../../res/girl.jpg')}                 style={[styles.image,{                 opacity:this.state.anim,//将动画对象赋值给需要改变的样式属性                 }]}/>            </View>        )    }

4、执行动画

componentDidMount() {         //timing动画        Animated.timing(//使用timin过度动画            this.state.anim,//要改变的动画对象            {                toValue: 1,//动画结束值                duration: 3000,//动画运行时间                easing: Easing.linear,//动画过渡曲线函数            }        ).start();//动画开始执行

随着动画的执行,样式属性的值会一直变化,即实现动画效果。

二、插值函数

我们可以只初始化一个动画对象,然后给多个样式属性赋值,通过interpolate()方法,我们可以将一个区间映射到另一个区间。

render() {        return (            <View style={styles.container}>                <Animted.Image source={require('../../res/girl.jpg')}                               style={[styles.image,{                               opacity:this.state.anim,//组件的opacity样式属性                               transform:[//组件的transform样式属性                               {scale:this.state.anim.interpolate({//组件的scale样式属性,将[0,1]区间映射到[1,2]区间                               inputRange:[0,1],//输入区间                               outputRange:[1,2]//输出区间                               })},                               {rotate:this.state.anim.interpolate({//组件的rotate样式属性,将[0,1]区间映射到['0deg','360deg]区间                               inputRange:[0,1],//输入区间                               outputRange:['0deg','360deg'],//输出区间                               })},                               ]                               }]}                />            </View>        )    }

其它代码不变,则随着动画的执行,图片的opacity,scale,rotate都会更改,产生一个淡入,放大,旋转同时进行的动画效果:
这里写图片描述

三、组合动画

RN为我们提供了三种组合动画方法:

  • sequence 顺序执行
  • parallel 同时执行
  • stagger 每隔一段时间开始执行行一个动画

例如一个弹出字幕的效果:
这里写图片描述

代码实现如下:

/** * Created by gyg on 2017/5/19. * Animated学习demo */'use strict'import React, {Component} from 'react';import {    StyleSheet,    Animated,    Easing,    View,    Image,    Text,    Dimensions,}from 'react-native';var deviceWidth=Dimensions.get('window').width;export default class AnimatedDemo extends Component {    // 构造    constructor(props) {        super(props);        // 初始状态        this.state = {            data: ['工行大公司都会', '好噶或更多更好的嘎', '规划i哈哈打开建行', '黑啊好的是根据卡号开个会看到个', '嘎机会更多机会关机定时关机'],            initAnims:[],//存放初始化的动画对象            anims: [],//存放动画函数        };        for(let i=0;i<this.state.data.length;i++){//遍历数据            this.state.initAnims.push(new Animated.Value(-250));//每条数据对应一个动画对象            this.state.anims.push(Animated.timing(this.state.initAnims[i],{//每条数据对应一个动画函数                duration:3500,                toValue:deviceWidth+250,                easing:Easing.linear,            }));        }    }    componentDidMount() {        Animated.stagger(1000,this.state.anims).start();//每隔1000ms开始执行动画数组中的一个动画    }    render() {        const views=this.state.data.map((text,i)=>{//每条数据映射一个动画组件            return(                <Animated.Text key={i}                    style={[styles.textview,{                    transform:[{                    translateX:this.state.initAnims[i],//设置translateX为动画值,这样动画执行的时候,translateX的值也会随之改变                    },                    {                    translateY:Math.floor(Math.random()*10),//产生0-9的一个随机数                    },                    ]}]}                >                    {text}                </Animated.Text>            )        });        return (            <View style={styles.container}>                {views}            </View>        )    }}const styles = StyleSheet.create({    container: {        flex: 1,        backgroundColor: 'white',        justifyContent: 'center',    },    textview:{        width:200,        paddingTop:10,        paddingBottom:10,        paddingLeft:20,        paddingRight:20,        backgroundColor:'rgba(0,0,0,0.5)',        borderRadius:10,        justifyContent:'center',        alignItems:'center',        fontSize:16,        color:'white',    },});