React Native学习react-native开发React Native

React Native 动画(LayoutAnimation)

2017-10-30  本文已影响888人  IAMCJ

平时进行 Native 开发的时候,为了更好的用户体验,我们会做一些动画效果,而在 React Native 中也提供了相应的动画API。

React Native 主要的动画分为两大类:

这篇文章主要说的是 LayoutAnimation 的用法,之后会写重点讲解 Animated 的文章。

LayoutAnimation

LayoutAnimation 是在布局发生变化时触发动画的接口,这意味着你需要通过修改布局(比如修改了组件的style、插入新组件)来触发动画。一个常用的调用此API的办法是调用 LayoutAnimation.configureNext,然后调用setState。

配置相关:

static configureNext(config: Config, onAnimationDidEnd?: Function) 
计划下一次布局要发生的动画。
@param config 表示动画相应的属性:
  duration 动画持续时间,单位是毫秒。
  create 配置创建新视图时的动画。
  update 配置被更新的视图的动画。

@param onAnimationDidEnd 当动画结束的时候被调用。只在iOS设备上支持。
@param onError 当动画产生错误的时候被调用。只在iOS设备上支持。

static create(duration: number, type, creationProp)
用来创建 configureNext 所需的 config 参数的辅助函数。

其中 config 参数格式参考:

LayoutAnimation.configureNext({
    duration: 700,   //动画持续时间
    create: {    //若是新布局的动画类型
        type: 'linear',  //线性模式,LayoutAnimation.Types.linear 写法亦可
        property: 'opacity'  //动画属性,除了opacity 还有一个 scaleXY 可以配置,LayoutAnimation.Properties.opacity 写法亦可
    },
    update: {  //若是布局更新的动画类型
        type: 'spring',   //弹跳模式
        springDamping: 0.4  //弹跳阻尼系数
    }
 });

create、update 的属性:

duration:动画持续时间(单位:毫秒),会覆盖 config 中设置的 duration。
delay:延迟指定时间(单位:毫秒)。
springDamping:弹跳动画阻尼系数(配合 spring 使用)。
initialVelocity:初始速度。

type:类型定义在LayoutAnimation.Types中:
spring:弹跳
linear:线性
easeInEaseOut:缓入缓出
easeIn:缓入
easeOut:缓出

property:类型定义在LayoutAnimation.Properties中:
opacity:透明度
scaleXY:缩放

示例:

import React, { Component } from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    View,
    Image,
    TouchableOpacity,
    Dimensions,
    LayoutAnimation,
} from 'react-native';

var screenW = Dimensions.get('window').width;
var screenH = Dimensions.get('window').height;

export default class extends Component {
    constructor(props) {
        super(props)

        this.state = {
            width: 100,
            height: 150,
            left:20,
            top:20,
        }
    }

    _clickStartAnimation() {
        LayoutAnimation.configureNext({
            duration: 1000,   //持续时间
            create: {
                type: LayoutAnimation.Types.spring,
                property: 'opacity',
            },
            update: {
                type: 'spring',
                springDamping: 0.4,
            }
        });
        this.setState({
            width: this.state.width + 40,
            height: this.state.height + 60,
            left: this.state.left + 20,
            top: this.state.top + 50,
        });
    }

    render(){
        return (
            <View style={styles.mainStyle}>

                <Image style={{width:this.state.width,height:this.state.height,position:'absolute',left:this.state.left, top:this.state.top}}
                       source={{uri:'beauty.jpg'}}>
                </Image>

                <TouchableOpacity style={{width:200,height:50,backgroundColor:'yellow',marginTop:40}} onPress={this._clickStartAnimation.bind(this)}>
                    <Text style={{width:200,height:50,textAlign:'center',lineHeight:50}}>点击开始动画</Text>
                </TouchableOpacity>
            </View>
        );
    }
}

效果图:


效果图.gif

实现拆解:
在 update 中的 type 为 spring,每次点击按钮,图片都会改变宽高和位置,会有一个移动和缩放的动画效果。

人民币装入红包动画:

import React, { Component } from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    View,
    Image,
    TouchableOpacity,
    Dimensions,
    LayoutAnimation,
} from 'react-native';

var anima = {
    duration: 1000,   //持续时间
    create: {
        type: LayoutAnimation.Types.spring,
        property: LayoutAnimation.Properties.scaleXY,
    },
    update: {
        type: 'easeOut',
    }
};

export default class extends Component {
    constructor(props) {
        super(props)

        this.state = {
            width: 200,
            height: 100,
            left:100,
            top:20,
        }
    }

    _clickStartAnimation() {

        LayoutAnimation.configureNext(anima,()=>{
            this.setState({
                top: 20,
            });
        });
        this.setState({
            top: this.state.top + 200,
        });
    }

    _setTimer(){
        // 先开始一次动画
        this._clickStartAnimation();
        // 创建定时器
        this.timer =  setInterval(this._clickStartAnimation.bind(this),1200);
    }

    render(){
        return (
            <View style={styles.mainStyle}>

                <Image style={{width:this.state.width,height:this.state.height,position:'absolute',left:this.state.left, top:this.state.top}}
                       source={{uri:'100.jpg'}}>
                </Image>

                <View style={{
                    width:240,
                    height:120,
                    position:'absolute',
                    left:80,
                    top:200,
                    backgroundColor:'red',
                }}>
                    <Text style={{color:'#FFD700',fontSize:90,lineHeight:104,width:240, textAlign:'center'}}>红包</Text>
                </View>

                <TouchableOpacity style={{width:200,height:50,backgroundColor:'yellow',marginTop:40}} onPress={this._setTimer.bind(this)}>
                    <Text style={{width:200,height:50,textAlign:'center',lineHeight:50}}>点击开始动画</Text>
                </TouchableOpacity>
            </View>
        );
    }
}

效果图:

红包效果图.gif

实现拆解:
首先创建一个 config 变量,1秒的持续时间,type 为 easeOut,然后在点击按钮之后,先执行一次动画,并同时开启定时器,1.2秒执行一次动画,在每次的动画执行完成之后,让100元回到原位,然后再次执行动画。

魔法现金动画:

import React, { Component } from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    View,
    Image,
    TouchableOpacity,
    Dimensions,
    LayoutAnimation,
} from 'react-native';

var anima = {
    duration: 1000,   //持续时间
    create: {
        type: LayoutAnimation.Types.linear,
        property: LayoutAnimation.Properties.scaleXY,
    },
    update: {
        type: 'linear',
    }
};

export default class extends Component {
    constructor(props) {
        super(props)

        this.state = {
            width: 250,
            height: 125,
            show:false,
        }
    }

    _clickStartAnimation() {

        LayoutAnimation.configureNext(anima,()=>{});
        this.setState({
            show: true,
        });
    }

    render(){

        var secondMoney = this.state.show ? (
            <Image style={{width:this.state.width,height:this.state.height}}
                   source={{uri:'100.jpg'}}>
            </Image>
        ) : null;

        return (
            <View style={styles.mainStyle}>

                <Image style={{width:this.state.width,height:this.state.height}}
                       source={{uri:'100.jpg'}}>
                </Image>

                {secondMoney}

                <TouchableOpacity style={{width:200,height:50,backgroundColor:'yellow',marginTop:40}} onPress={this._clickStartAnimation.bind(this)}>
                    <Text style={{width:200,height:50,textAlign:'center',lineHeight:50}}>魔法现金</Text>
                </TouchableOpacity>
            </View>
        );
    }
}

效果图:

魔法现金效果图.gif

实现拆解:
首先创建一个 config 变量,1秒的持续时间,type 为 linear,property 为
scaleXY,然后在点击按钮之后,修改 state.show 为 true,然后根据这个属性就会加载出一个新的100元图片,因为是创建,不是更新,所以新的100元图片是执行的 create 内的动画效果,原来的100元图片和按钮则是执行的 update 效果。

LayoutAnimation.create

如果觉得上面的代码太繁杂,还可以通过 LayoutAnimation.create 这个函数更简单的创建一个config,也可以实现上面的动画效果。

create函数接受三个参数:

用法:

...
_clickStartAnimation() {
    LayoutAnimation.configureNext(LayoutAnimation.create(1000,
        LayoutAnimation.Types.linear,
        LayoutAnimation.Properties.scaleXY));
    this.setState({
        show: true,
    });
}
...

效果图和上面一样,参考上面即可。

LayoutAnimation.Presets

系统也为我们提供了3个默认的动画,定义在LayoutAnimation.Presets中:

可以使用这种方式创建一些简单的动画效果。

用法:

...
_clickStartAnimation() {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);                
    this.setState({
        show: true,    
    });
}
...

这个效果和上面类似,区别在于这个默认 Properties 是 opacity,创建过程是透明度的变化。

效果图:


Presets效果图.gif

LayoutAnimation 使用总结:

Demo在这里,不麻烦的话 star 一下哈,谢谢!

上一篇下一篇

猜你喜欢

热点阅读