React Native动画入门全解析

动画

React Native 提供了两个互补的动画系统:

  • 用于创建精细的交互控制动画Animated
  • 用于全局的布局动画LayoutAnimation

Animated

Animated通过 **.start/stop **控制动画按顺序执行,Animated中有四个可以动画化的组件:

  • Text
  • View
  • Image
  • ScrollView

Animated提供了两种类型的值:

  • Animated.Value()用于单个值

  • Animated.ValueXY()用于矢量值

    Animated.Value()可以绑定到样式或是其他属性上,也可以进行插值运算。单个Animated.Value()可以用在任意多个属性上。

透明效果实现:(不使用动画组件)

直接通过state修改

import React from 'react';
import { Animated, Text, View } from 'react-native';
export default class App extends React.Component {
  constructor(props) {
    super(props)
  
  this.state={
    touming:1,					//设置初始透明值为1
  }
}
    _onPress(){					//Text的点击事件回调
    this.setState({				//将透明值设置为0,完全透明
      touming:0
    });
    }
    
  
  render() {
    return (/*
        Animated.View是可以动画化的组件之一,直接用它包裹Text,opacity是透明度*/
     
        <View style={{width: 250, height: 50, backgroundColor: 'powderblue',opacity:this.state.touming}} >
          <Text style={{fontSize: 28, textAlign: 'center', margin: 10}} onPress={this._onPress.bind(this)}>点击透明</Text>
        </View>
     
    )
  }
}
透明效果实现:(使用原生组件的setNativeProps)
import React from 'react';
import { Animated, Text, View } from 'react-native';
export default class App extends React.Component {
  constructor(props) {
    super(props)
  
  this.state={
    touming:1,					//设置初始透明值为1
  }
}
    _onPress(){	
    		//Text的点击事件回调
        this.refs.view.setNativeProps({
            style:{
                opacity:0
            }
        });
    }
    
    
  
  render() {
    return (/*
        Animated.View是可以动画化的组件之一,直接用它包裹Text,opacity是透明度*/
     
        <View  ref="view"  style={{width: 250, height: 50, backgroundColor: 'powderblue',opacity:this.state.touming}} >
          <Text style={{fontSize: 28, textAlign: 'center', margin: 10}} onPress={this._onPress.bind(this)}>点击透明</Text>
        </View>
     
    )
  }
}
透明效果实现:(使用动画组件)
import React from 'react';
import { Animated, Text, View } from 'react-native';
export default class App extends React.Component {
  constructor(props) {
    super(props)
  
  this.state={
    touming:1,					//设置初始透明值为1
  }
}
    _onPress(){					//Text的点击事件回调
    this.setState({				//将透明值设置为0,完全透明
      touming:0
    });
    }
    
  
  render() {
    return (/*
        Animated.View是可以动画化的组件之一,直接用它包裹Text,opacity是透明度*/
      <View style={{flex: 1}}>
        <Animated.View style={{width: 250, height: 50, backgroundColor: 'powderblue',opacity:this.state.touming}} >
          <Text style={{fontSize: 28, textAlign: 'center', margin: 10}} onPress={this._onPress.bind(this)}>点击透明</Text>
        </Animated.View>
      </View>
    )
  }
}
动画用于创建动画的主要方法:
  • Animated.timing():最常用的动画类型,使一个值按照一个过渡曲线而随时间变化。
  • Animated.spring():弹簧效果,基础的单次弹跳物理模型实现的spring动画。
  • Animated.decay():衰变效果,以一个初始的速度和一个衰减系数逐渐减慢变为0。
动画实现组合动画的主要方式:
  • Animated.parallel():同时开始一个动画数组里的全部动画。默认情况下,如果有任何一个动画停止了,其余的也会被停止。可以通过stopTogether选项设置为false来取消这种关联。
  • Animated.sequence():按顺序执行一个动画数组里的动画,等待一个完成后再执行下一个。如果当前的动画被中止,后面的动画则不会继续执行。
  • Animated.stagger():一个动画数组,传入一个时间参数来设置队列动画间的延迟,即在前一个动画开始之后,隔一段指定时间才开始执行下一个动画里面的动画,并不关心前一个动画是否已经完成,所以有可能会出现同时执行(重叠)的情况。
简单组合动画,淡入淡出: Animated.timing()+Animated.sequence()

格式:Animated.timing(animateValue, conf), Animated.sequence(animations)

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


class DrDcView extends React.Component {
  
  state = {
    drdcAnim: new Animated.Value(1),  // 透明度初始值设为1
  }

 
  componentDidMount() {
      //按顺序执行一个动画数组里的动画,等待一个完成后再执行下一个。如果当前的动画被中止,后面的动画则不会继续执行。
    Animated.sequence([	//通过sequence(顺序执行)组合使用,实现淡入淡出。
        /*.timing方法传入两个参数,第一个是Value,第二个是config,有以下:
       	 	duration:动画持续的时间(单位是毫秒),默认为500。
  			easing:一个用于定义曲线的渐变函数。Easing模预置了 linear、ease、elastic、bezier 等诸			多缓动特性。iOS默认为Easing.inOut(Easing.ease),。
  			delay:开始动画前的延迟时间(毫秒),默认为0。
        */
      Animated.timing(                  // 随时间变化而执行动画
        this.state.drdcAnim,            // 动画中的变量值
        {
          toValue: 0,                   // 透明度最终变为0
          duration: 7000,                // 让动画持续一段时间
        }
      ),
      Animated.timing(                  
        this.state.drdcAnim,            
        {
          toValue: 1,                  
          duration: 7000,                
        }
      )
    ]).start();
                     // 开始执行动画
  }

  render() {
    let { drdcAnim } = this.state;

    return (
      <Animated.View                 // 使用专门的可动画化的View组件
        style={{
          ...this.props.style,
          opacity: drdcAnim,         // 将透明度指定为动画变量值
        }}
      >
        {this.props.children}
      </Animated.View>
    );
  }
}


// 在组件中像使用`View`那样去使用DrDcView
export default class App extends React.Component {
  render() {
    return (
      <View style={{flex: 1}}>
        <DrDcView style={{width: 250, height: 50, backgroundColor: 'powderblue'}}>
          <Text style={{fontSize: 28, textAlign: 'center', margin: 10}}> 淡入淡出</Text>
        </DrDcView>
        
      </View>
    )
  }
}
简单弹跳效果: Animated.spring()

格式:Animated.spring(animateValue, conf)

import React from 'react';
import { Animated, Text, View ,Easing,StyleSheet,Image,TouchableOpacity} from 'react-native';
export default class AnimatedSpring extends React.Component{
    constructor(props){
        super(props);
        this.state={
           springValue:new Animated.Value(1)					//设置原始大小为1
         };
         this.springAnimated = Animated.spring(				/*传入两个参数,第一个参数是Value,			第二个参数是config:有以下 
         	friction: 控制“弹跳系数”、夸张系数,默认为7。
  			tension: 控制速度,默认为40。
 			speed: 控制动画的速度,默认为12。
  			bounciness: 反弹系数,默认为8。:*/
             this.state.springValue,
             {
                 toValue:1,
                 friction:4,            //控制弹跳系数
                 tension:20,                //控制速度
             }
         );
        
    } 
     _startAnimated(){				//TouchableOpacity的回调,在内部将图片初始大小设为0.2
             this.state.springValue.setValue(0.2);
             this.springAnimated.start();		//启动动画
         } 
         render(){
             /*
             transform是类型转换,接受一组转换对象。每个对象指定将转换为键的属性,以及要在转换中使用的值。一般用于带符号的值,下面代码有明确表示*/
             return(
                 <View style={styles.mainStyle}>
                     <Animated.View
                         style={{
                                width:300,height:40,
                                transform:[{	//类型转换
                                scale:this.state.springValue}]
                         }
                     }>
                        <Image ref="image" style={{width:299,height:39}}
                                source={require('./img/spring.png')}>
                         </Image>
                     </Animated.View>
                        <TouchableOpacity style={styles.touch} onPress={this._startAnimated.bind(this)}>
                             <Text style={{width:200,height:100,textAlign:'center',lineHeight:100}}>点击开始动画</Text>
                         </TouchableOpacity>
                 </View>
             );
         }     
}
const styles = StyleSheet.create({
    mainStyle: {
     flex:1,
     flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    },
    touch:{
       
        justifyContent: 'center',
        alignItems: 'center',
    }
  });

简单移动衰变效果: Animated.decay()

格式:Animated.decay(animateValue, conf)

import React from 'react';
import { Animated, Text, View ,Easing,StyleSheet,Image,TouchableOpacity} from 'react-native';

const styles = StyleSheet.create({
    mainStyle: {
     flex:1,
     flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    },
    touch:{
       
        justifyContent: 'center',
        alignItems: 'center',
    }
  });




export default class AnimDecay extends React.Component{
    constructor(props){
        super(props);
        this.state={
            decayValue:new Animated.ValueXY({x:0,y:0}),//用ValueXY表示矢量单位,表示初始坐标。
    }
    this.decayAnim=Animated.decay(
        /**传入两个参数,第一个参数是Value,			第二个参数是config
         * conf参数格式:
            velocity: 起始速度,必填参数。
             deceleration: 速度衰减比例,默认为0.997。

         */
        this.state.decayValue,{
            velocity:6,
            deceleration:0.88,
        }
    );
    }
    _startAnimated(){
        this.decayAnim.start();         //控制动画开关
    }
    render(){
        return(
            <View style={styles.mainStyle}>
                <Animated.View 
                style={{
                    width:80,
                    height:122,
                    transform:[{        //类型转换
                        translateX:this.state.decayValue.x
                    },{
                        translateY:this.state.decayValue.y
                    }]
                }}>
                        <Image
                        style={{width:80,height:122}} source={require('./img/spring.png')}></Image>
                </Animated.View>
                <TouchableOpacity style={styles.touch} onPress={this._startAnimated.bind(this)}>
                <Text style={{width:200,height:100,textAlign:'center',lineHeight:100}}>点击开始动画</Text>
                </TouchableOpacity>

            </View>
        )
    }
}
插值函数 interpolate()非常强大的一个函数

`**interpolate() **函数允许输入范围映射到不同的输出范围。默认情况下,它将推断超出给定范围的曲线,但也可以限制输出值。它默认使用线性插值,但也支持缓动功能。

将0-1范围转换为0-100范围的简单映射将是:

	value.interpolate({
  		inputRange: [0, 1],
 		 outputRange: [0, 100]
		});

Animated.Value从0调到1,但是将位置从150px设置为0px,并将不透明度从0设置为1:

style={{
    opacity: this.state.DrDcAnim, // Binds directly
    transform: [{
      translateY: this.state.DrDcAnim.interpolate({
        inputRange: [0, 1],
        outputRange: [150, 0]  // 0 : 150, 0.5 : 75, 1 : 0
      }),
    }],
  }}

**interpolate() ** 还支持定义多个区间段落,常用来定义静止区间等。

要让输入在接近-300时取相反值,然后在输入接近-100时到达0,然后在输入接近0时又回到1,接着一直到输入到100的过程中逐步回到0,最后形成一个始终为0的静止区间,对于任何大于100的输入都返回0.

value.interpolate({
  inputRange: [-300, -100, 0, 100, 101],
  outputRange: [300, 0, 1, 0, 0]
});

**interpolate() ** 还支持到字符串的映射,从而可以实现颜色以及带有单位的值的动画变换例如你可以像下面这样实现一个旋转动画:

value.interpolate({
  inputRange: [0, 360],
  outputRange: ["0deg", "360deg"]
});

稍微炫酷的动画:Animated.parallel()+ Animated.timing()

格式:Animated.parallel(Animates, [conf])

import React from 'react';
import { Animated, Text, View ,Easing,StyleSheet,Image,TouchableOpacity} from 'react-native';


const styles = StyleSheet.create({
    mainStyle: {
     flex:1,
     flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    },
    touch:{
       
        justifyContent: 'center',
        alignItems: 'center',
    }
  });


export default class AnimParallel extends React.Component{
    constructor(props) {
        super(props);

        this.state = {
                touOpacityValue: new Animated.Value(1),//设置图片透明度初始值
                touxiangValue:new Animated.Value(0),//设置位移动画初始值
        }
        this.parallelAnimated=Animated.parallel(/**
            传入两个参数,第一个参数是Animates<Array>,第二个参数是config:
            {
            stopTogether: false
            默认情况下,如果有任何一个动画停止了,其余的也会被停止。可以通过stopTogether 选项设置为 false 来取消这种关联
                }
            */
            [Animated.timing(
                this.state.touOpacityValue,{//在两秒中将图片动画显示出来
                    toValue:1,
                    duration:2000,
                }
            ),
        Animated.timing(
            this.state.touxiangValue,
            {//在四秒内完成其他图片的位移
                toValue:1,
                duration:4000,
            }
        ),],{
            stopTogether:false//取消关联,不会因为一个停止而其他动画停止
        }
        )

}
_startAnimated() {
    this.state.touOpacityValue.setValue(0);//透明度设为0
    this.state.touxiangValue.setValue(0);//初始位置
    this.parallelAnimated.start();//启动动画
}
render(){
    const touOpacity=this.state.touOpacityValue.interpolate({//闪屏效果,
        inputRange:[0,0.2,0.4,0.6,0.8,1],
        outputRange:[0,1,0,1,0,1]
    })
    const top=this.state.touxiangValue.interpolate({//项链上移到指定位置,
        inputRange:[0,1],
        outputRange:[440,200]
    })
    const left=this.state.touxiangValue.interpolate({//眼镜移到指定位置,
        inputRange:[0,1],
        outputRange:[-113,140]
    })
    const rotateZ=this.state.touxiangValue.interpolate({//眼镜旋转,
        inputRange:[0,1],
        outputRange:['0deg','360deg']
    })
    return(
        <View style={styles.mainStyle}>

        {/*// 头像*/}
        <Animated.View
            style={{
                width: 540,
                height: 414,
                opacity:touOpacity,//透明度调节
            }}
        >
            <Image  style={{width:540,height:414}}
                   source={require('./img/touxiang.jpg')}>
            </Image>
        </Animated.View>

        {/*// 项链*/}
        <Animated.View
            style={{
                width: 140,
                height: 140,
                position: 'absolute',//两个值:relative'为默认,,absolute表示根据父级来定位
                top:top,//项链高度调节
                left:120,//项链的x轴位置
            }}
        >
            <Image ref="image" style={{width:140,height:140,resizeMode:'stretch'}}
                   source={require('./img/xianglian.png')}>
            </Image>
        </Animated.View>

        <View
            style={{
                width: 375,
                height: 200,
                backgroundColor:'white',
            }}
        />

        {/*// 眼镜*/}
        <Animated.View
            style={{
                width: 120,
                height: 25,
                position: 'absolute',
                top:90,
                left:left,
                transform:[
                    {rotateZ:rotateZ}
                ],
            }}
        >
            <Image ref="image" style={{width:120,height:25,
            resizeMode:'stretch'}}//resizeMode表示图片显示样式有这些值'cover', 'contain', 'stretch', 'repeat', 'center'
                   source={require('./img/yanjing.png')}>
            </Image>
        </Animated.View>

        <TouchableOpacity style={styles.touchStyle} onPress={this._startAnimated.bind(this)}>
            <Text style={{width:200,height:100,textAlign:'center',lineHeight:100}}>点击开始动画</Text>
        </TouchableOpacity>
    </View>
    );

}

}


简单翻转,旋转,平移,缩放:主要运用interpolate() +Animated.timing()
import React from 'react';
import { Animated, Text, View ,Easing,StyleSheet,Image,TouchableOpacity} from 'react-native';

export default class Mixture extends React.Component {

    constructor(props) {
        super(props)

        this.state = {
            animatedValue: new Animated.Value(0),			//设置初始值
        }

        this.rotateAnimated = Animated.timing(
            this.state.animatedValue,
            {
                toValue: 1,
                duration: 8000,
              
            }
        );
    }

    _startAnimated() {
        this.state.animatedValue.setValue(0);		//再次将初始值设为0
        this.rotateAnimated.start(() => this._startAnimated());
        //启动动画,并重复调用TouchableOpacity的回调,无限循环。
    }

    render(){

        const rotateZ = this.state.animatedValue.interpolate({//插值映射,,rotateZ表示旋转
            inputRange: [0, 1],
            outputRange: ['0deg', '360deg']//将[0,1]映射成0-360旋转。
        });

        const opacity = this.state.animatedValue.interpolate({//opacity表示透明度
            inputRange: [0, 0.5, 1],
            outputRange: [0, 1, 0]			//将[0,1]映射成透明-不透明-透明变化。
        });

        const rotateX = this.state.animatedValue.interpolate({//rotateX表示上下翻转
            inputRange: [0, 0.5, 1],
            outputRange: ['0deg', '180deg', '0deg']//[0,1]映射成0-360翻转
        });

        const textSize = this.state.animatedValue.interpolate({//textSize表示字体大小
            inputRange: [0, 0.5, 1],
            outputRange: [18, 32, 18]//[0,1]映射成18-32-18号字体
        });

        const marginLeft = this.state.animatedValue.interpolate({//marginLeft表示左边距
            inputRange: [0, 0.5, 1],
            outputRange: [0, 200, 0]		//[0,1]映射成0-200-0距离
        });

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

                <Animated.View
                    style={{
                        marginTop: 10,
                        width: 100,
                        height: 100,
                        transform: [//类型转换
                            {rotateZ:rotateZ},
                        ]
                    }}
                >
                    <Image style={{width:100,height:100}}
                           source={require('./img/qwe.png')}>
                    </Image>
                </Animated.View>

                <Animated.View
                    style={{
                        marginTop: 10,
                        width: 100,
                        height: 100,
                        opacity:opacity,
                        backgroundColor:'red',
                    }}
                />

                <Animated.Text
                    style={{
                        marginTop: 10,
                        width:100,
                        fontSize: 18,
                        color: 'white',
                        backgroundColor:'red',
                        transform: [//类型转换
                            {rotateX:rotateX},
                        ]
                    }}
                >
                    这是一个180翻转。
                </Animated.Text>

                <Animated.Text
                    style={{
                        marginTop: 10,
                        height: 100,
                        lineHeight: 100,
                        fontSize: textSize,
                        color: 'red'
                    }}
                >
                   这是字体缩小和放大
                </Animated.Text>

                <Animated.View
                    style={{
                        marginTop: 10,
                        width: 100,
                        height: 100,
                        marginLeft:marginLeft,
                        backgroundColor:'red',
                    }}
                />

                <TouchableOpacity style={styles.touchStyle} onPress={this._startAnimated.bind(this)}>
                    <Text style={{width:200,height:100,textAlign:'center',lineHeight:100}}>点击开始动画</Text>
                </TouchableOpacity>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    mainStyle: {
     flex:1,
     
    },
   
  });



带有延迟的动画:Animated.stagger()+Animated.timing()

格式:Animated.stagger(delayTime, Animates)

import React from 'react';
import { Animated, Text, View ,Easing,StyleSheet,Image,TouchableOpacity} from 'react-native';


const styles = StyleSheet.create({
    mainStyle: {
     flex:1,
     flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    },
    touch:{
       
        justifyContent: 'center',
        alignItems: 'center',
    }
  });




export default class AnimatedStagger extends React.Component {

    constructor(props) {
        super(props);
        
        this.state={
            blackValue:new Animated.Value(0),//位移初始值
             yellowValue:new Animated.Value(0),
        };
        this.staggerAnim=Animated.stagger(3000,
            /**
             * 接受两个参数delayTime<Number>, Animates<Array>
             * delayTime表示一个动画后下一个动画执行前的延迟,
             */
            [Animated.timing(
                this.state.blackValue,{
                    toValue:1,
                    duration:6000,
                }
            ),
            Animated.timing(
                this.state.yellowValue,{
                    toValue:1,
                    duration:8000,
                }
            ),
            ])
    }
    _startAnimated() {
        this.staggerAnim.start();
    }
    render(){

        const blackMarginLeft = this.state.blackValue.interpolate({
            inputRange: [0,1],
            outputRange: [0,200]
        });

        const yellowMarginLeft = this.state.yellowValue.interpolate({
            inputRange: [0,1],
            outputRange: [0,300]
        });

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

                {/*// 黑色*/}
                <Animated.View
                    style={{
                        width: 100,
                        height: 100,
                        backgroundColor:'black',
                        marginLeft:blackMarginLeft,
                    }}
                >
                </Animated.View>


                {/*// 黄色*/}
                <Animated.View
                    style={{
                        width: 100,
                        height: 100,
                        backgroundColor:'yellow',
                        marginLeft:yellowMarginLeft,
                    }}
                >
                </Animated.View>

                <TouchableOpacity style={styles.touchStyle} onPress={this._startAnimated.bind(this)}>
                    <Text style={{width:200,height:100,textAlign:'center',lineHeight:100}}>点击开始动画</Text>
                </TouchableOpacity>
            </View>
        );
    }
}

其他:参考文档

跟踪动态值

动画中所设的值还可以通过跟踪别的值得到。你只要把 toValue 设置成另一个动态值而不是一个普通数字

跟踪手势

Animated.event是Animated中与输入有关的部分,允许手势或其它事件直接绑定到动态值上。它通过一个结构化的映射语法来完成,使得复杂事件对象中的值可以被正确的解开。是一个数组,允许同时映射多个值,然后数组的每一个元素是一个嵌套的对象。

Animated.event(argMapping, config)

Config参数有以下这些属性:

  • listener:可选的异步监听函数
  • useNativeDriver:启用原生动画驱动。默认不启用(false)。
响应当前的动画值

你可能会注意到这里没有一个明显的方法来在动画的过程中读取当前的值 - 这是出于优化的角度考虑,有些值只有在原生代码运行阶段中才知道。如果你需要在JavaScript中响应当前的值,有两种可能的办法:

  • spring.stopAnimation(callback)会停止动画并且把最终的值作为参数传递给回调函数callback-这在处理手势动画的时候非常有用。
  • spring.addListener(callback)在会动画的执行过程中持续异步调用callback回调函数,提供一个最近的值作为参数。这在用于触发状态切换的时候非常有用,譬如当用户拖拽一个东西靠近的时候弹出一个新的气泡选项。不过这个状态切换可能并不会十分灵敏,因为它不像许多连续手势操作(如旋转)那样在60fps下运行。
在动画结束时弹出对话框:spring.stopAnimation(callback)

在上面的弹跳效果的demo中加上下面这段代码,可以实现停止动画并弹出对话框

+++var iii=0;

_startAnimated() {
      this.staggerAnim.start();
+++  if(iii===0){
+++          iii=1
+++       }else{
           
	     +++this.state.blackValue.stopAnimation(Value=>{
+++           Alert.alert(//对话框
+++               '跳完了',
+++               JSON.stringify(Value),//解析value
+++               [
+++                   {text:'cancel',onPress:()=>
+++          {}}
+++               ]
+++          )
+++      })	}	
                                                
}
                                                //////////////////////////////或者使用  .addListener,它会一直监听动画并返回Value,
                                                
             +++var iii=0;

_startAnimated() {
      this.staggerAnim.start();
+++  if(iii===0){
+++          iii=1
+++       }else{
           
	     +++this.state.blackValue.addListener(Value=>{
+++           Alert.alert(//对话框
+++               '跳完了',
+++               JSON.stringify(Value),//解析value
+++               [
+++                   {text:'cancel',onPress:()=>
+++          {}}
+++               ]
+++          )
+++      })	}	
                                                
}                                   
                                                

启用原生动画驱动

Animated的API是可序列化的(即可转化为字符串表达以便通信或存储)。通过启用原生驱动我们在启动动画前就把其所有配置信息都发送到原生端,利用原生代码在UI线程执行动画,而不用每一帧都在两端间来回沟通。如此一来,动画一开始就完全脱离了JS线程,因此此时即便JS线程被卡住,也不会影响到动画了。

在动画中启用原生驱动非常简单只需在开始动画之前,在动画配置中加入一行。 useNativeDriver: true

动画值在不同的驱动方式之间是不能兼容的。因此如果你在某个动画中启用了原生驱动,那么所有和此动画依赖相同动画值的其他动画也必须启用原生驱动。

LayoutAnimation API

LayoutAnimation允许你在全局范围内创建和更新动画,这些动画会在下一次渲染或布局周期运行。它常用来更新 flexbox 布局,因为它可以无需测量或者计算特定属性就能直接产生动画。尤其是当布局变化可能影响到父节点(譬如“查看更多”展开动画既增加父节点的尺寸又会将位于本行之下的所有行向下推动)时,如果不使用LayoutAnimation,可能就需要显式声明组件的坐标,才能使得所有受影响的组件能够同步运行动画。

​ 一个常用的调度此API的方法是调用LayoutAnimation.configureNext,然后调用setState,且如果在Android中使用此动画,还需要在代码中启用:

import { UIManager } from 'react-native';

UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);

这段代码可以写在任何组件加载之前

查看方法
  • configureNext :

    ​ configureNext(config, onAnimationDidEnd):

    ​ config: 类型object 必填。

    ​ duration 动画持续时间,单位是毫秒。
    ​ create, 配置创建新视图时的动画。
    ​ update, 配置被更新的视图的动画。

    ​ onAnimationDidEnd: 类型function 非必填

    ​ 动画结束后的回调,目前仅IOS可用

  • create:

    ​ create(duration, type, creationProp):

    ​ type;//更新时类型为

    ​ creationProp://创建时类型为

  • checkConfig:用来创建configureNext所需的配参数的辅助函数。

查看属性
  • creat,update的属性:

    	duration:动画持续时间(单位:毫秒),会覆盖 config 中设置的 duration。
    	delay:延迟指定时间(单位:毫秒)。
    	springDamping:弹跳动画阻尼系数(配合 spring 使用)。
    	initialVelocity:初始速度。
    	type:类型定义在LayoutAnimation.Types中:
    	spring:弹跳
    	linear:线性
    	easeInEaseOut:缓入缓出
    	easeIn:缓入
    	easeOut:缓出
    	property:类型定义在LayoutAnimation.Properties中:
    	opacity:透明度
    	scaleXY:缩放
    
    
布局创建:LayoutAnimation.configureNext()
import React from 'react';
import {
     Animated,
      Text,
       View ,
       Easing,
       StyleSheet,
       Image,
       TouchableOpacity,
        Platform,
        Dimensions,
        LayoutAnimation

    } from 'react-native';
    import { UIManager } from 'react-native';

UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);

const styles = StyleSheet.create({
    mainStyle: {
     flex:1,
     flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    },
    touch:{
       
        justifyContent: 'center',
        alignItems: 'center',
    }
  });

var anima={//创建一个 LayoutAnimation.configureNext的config属性。
    duration:1000,
    create:{//创建
        type:LayoutAnimation.Types.linear,//类型为线性
        property:LayoutAnimation.Properties.scaleXY,//方式为缩放
    },
    update:{//更新
        type:'linear'
    }
};
export default class extends React.Component{
    constructor(props){
        super(props)
        this.state={
            width:250,
            height:125,
            show:false,//是否可见
        }
    }
    _clickStartAnimation(){
        LayoutAnimation.configureNext(anima,()=>{});
        this.setState({
            show:true,
        });
    }
    render(){
        var second=this.state.show?(//创建第二个控件,进行判断是否可见
            <View style={{width:this.state.width,height:this.state.height,backgroundColor:'blue'}}>
            <Text style={{alignItems:'center',justifyContent:'center',textAlign:'center'}}>第二个</Text>
            </View>
        ):null
    return(
        <View style={styles.mainStyle}>
             <View style={{width:this.state.width,height:this.state.height,backgroundColor:'blue'}}>
            <Text style={{alignItems:'center',justifyContent:'center',textAlign:'center'}}>第一个</Text>
            </View>
            {second}
            <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>
    )
    }
}


LayoutAnimation.Presets:当中提供了三个预置动画效果,不需要我们自己去定义和实现创建和更新时的动画

1551863770589

更改上面代码,实现不同效果:

 _clickStartAnimation(){
        LayoutAnimation.configureNext(
            LayoutAnimation.Presets.spring);//改为弹性
        this.setState({
            show:true,
        });
    }
//////////////////////////////////////////
 _clickStartAnimation(){
        LayoutAnimation.configureNext(
            LayoutAnimation.Presets.easeInEaseOut);//改为缓入缓出
        this.setState({
            show:true,
        });
    }
/////////////////////////////////////
   _clickStartAnimation(){
        LayoutAnimation.configureNext(
            LayoutAnimation.Presets.linear);//改为线性
        this.setState({
            show:true,
        });
    }

本文大量借鉴了其他作者的心血和官网文档:
RN中文网
https://www.jianshu.com/p/7fd37d8ed138
https://www.cnblogs.com/vajoy/p/5299315.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值