ReactNativeReact Native

React Native 动画

2019-07-05  本文已影响0人  一亩三分甜

1.Animated.timing()

最常用的动画类型,是一个值按照一个过渡曲线而随时间变化,格式如下:Animated.timing(animateValue,conf<Object>),conf参数格式:

{
duration:动画持续的时间(单位是毫秒),默认为500。
easing:一个用户定义曲线的渐变函数。Easing模预置了linear、ease、elastic、bezier等诸多欢动特性。iOS默认为Easing.inOut(Easing.ease)。
delay:开始动画前的延迟时间(毫秒),默认为0。
}
export default class Opacity extends Component {
    constructor(props) {
        super(props)
        this.state = {
            fadeOutOpacity: new Animated.Value(1),
        };
        this.fadeOutAnimated = Animated.timing(
            this.state.fadeOutOpacity,
            {
                toValue: 0,//透明度动画最终值
                duration: 3000,//动画时长3000毫秒
                easing: Easing.linear,
            }
        );
    }
    _startAnimated() {
        this.fadeOutAnimated.start(() => this.state.fadeOutOpacity.setValue(1));
    }

    render() {
        return (
        <View style={styles.container}>
                <Animated.View style={{ width: 360, height: 300, opacity: this.state.fadeOutOpacity }}>
                    <Image ref="iamge" style={{ width: 360, height: 300 }} source={require('./beauty.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>
        );
    }
}
const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#ecf0f1',
        padding: 8,
    },
    paragraph: {
        margin: 24,
        fontSize: 18,
        fontWeight: 'bold',
        textAlign: 'center',
    },
    touchStyle:{
        flex:1,
        justifyContent:'center',
        alignItems:'center',
        textAlign:'center',
        alignSelf:'center',
    },
});
0.gif

interpolate()函数

export default class Mixture extends Component {
    constructor(props) {
        super(props)
        this.state = {
            animatedValue: new Animated.Value(0),
        }
        this.rotateAnimated = Animated.timing(
            this.state.animatedValue,
            {
                toValue: 1,
                duration: 3000,
                easing: Easing.in,
            }
        );
    }
    _startAnimated() {
        this.state.animatedValue.setValue(0);
        this.rotateAnimated.start(() => this._startAnimated());
    }
    render() {
        const rotateZ = this.state.animatedValue.interpolate({
            inputRange: [0, 1],
            outputRange: ['0deg', '360deg']
        });
        const opacity = this.state.animatedValue.interpolate({
            inputRange: [0, 0.5, 1],
            outputRange: [0, 1, 0]
        });
        const rotateX = this.state.animatedValue.interpolate({
            inputRange: [0, 0.5, 1],
            outputRange: ['0deg', '180deg', '0deg']
        });
        const textSize = this.state.animatedValue.interpolate({
            inputRange: [0, 0.5, 1],
            outputRange: [18, 32, 18]
        });
        const marginLeft = this.state.animatedValue.interpolate({
            inputRange: [0, 0.5, 1],
            outputRange: [0, 200, 0]
        });
        return (
            <View style={styles.container}>
                <Animated.View style={{
                    marginTop: 10,
                    width: 100,
                    height: 100,
                    transform: [{ rotateZ: rotateZ },]
                }}>
                    <Image style={{ width: 100, height: 100 }}
                        source={require('./stream.jpg')}
                    >
                    </Image>
                </Animated.View>
                <Animated.View
                    style={{
                        marginTop: 2,
                        width: 100,
                        height: 100,
                        opacity: opacity,
                        backgroundColor: 'red',
                    }}
                />
                <Animated.Text
                    style={{
                        mariginTop: 2,
                        width: 100,
                        fontSize:18,
                        color:'white',
                        backgroundColor:'red',
                        transform:[{rotateX:rotateX}]
                    }}
                >
                红酥手,黄藤酒,满城春色宫墙柳。
                </Animated.Text>
                <Animated.Text
                   style={{
                       marginTop:2,
                       height:100,
                       lineHeight:100,
                       fontSize:textSize,
                       color:'red'
                   }}
                >
                    春如旧,人空瘦,泪痕红浥鲛绡透。
                </Animated.Text>
                <Animated.View
                style={{
                    marginTop:2,
                    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({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#ecf0f1',
        padding: 8,
    },
    touchStyle:{
        flex:1,
        marginTop:6,
        justifyContent:'center',
        alignItems:'center',
        textAlign:'center',
        alignSelf:'center',
    },
});
1.gif

2.Animated.spring()

弹簧效果,基础的单次弹跳物理模型实现的 spring 动画,格式如下:
Animated.spring(animateValue, conf<Object>),conf参数格式:

{
  friction: 控制“弹跳系数”、夸张系数,默认为7。
  tension: 控制速度,默认为40。
  speed: 控制动画的速度,默认为12。
  bounciness: 反弹系数,默认为8。
}
export default class AnimatedSpring extends Component {
    constructor(props) {
        super(props);
        this.state = {
            springValue: new Animated.Value(1),
        };
        this.springAnimated = Animated.spring(
            this.state.springValue,
            {
                toValue: 1,
                friction: 2,//弹跳系数
                tension: 10,//控制速度
            }
        );
    };
    _startAnimated() {
        this.state.springValue.setValue(0.1);
        this.springAnimated.start();
    }
    render() {
        return (
            <View style={styles.container}>
                <Animated.View
                    style={{
                        width: 282,
                        height: 152,
                        transform: [{ scale: this.state.springValue }]
                    }}
                >
                    <Image ref='image' style={{ width: 282, height: 152 }}
                        source={require('./scenery.jpg')}
                    >
                    </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>
        )
    }
}
const styles = StyleSheet.create({
       container:{
          flex:1,
          justifyContent:'center',
          alignItems:'center',
          backgroundColor:'#ecf0f1',
          padding:8,
          width:'100%',
          height:'100%',
       },
       touchStyle:{
          flex:1,
          justifyContent:'center',
          alignItems:'center',
          textAlign:'center',
          alignSelf:'center',
          marginTop:6,
       },
});
2.gif

3.Animated.decay()

衰变效果,以一个初始的速度和一个衰减系数逐渐减慢变为0,格式如下:
Animated.decay(animateValue, conf<Object>),conf参数格式:

{
  velocity: 起始速度,必填参数。
  deceleration: 速度衰减比例,默认为0.997。
}
export default class AnimatedDecay extends Component {

    constructor(props) {
        super(props);

        this.state = {
            decayValue: new Animated.ValueXY({x:0,y:0}),
        };

        this.decayAnimated = Animated.decay(
            this.state.decayValue,
            {
                velocity: 5,       // 起始速度,必填
                deceleration: 0.95,  // 速度衰减比例,默认为0.997
            }
        );
    }

    _startAnimated() {
        this.decayAnimated.start();
    }

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

                <Animated.View
                    style={{
                        width: 100,
                        height: 150,
                        transform:[
                            {translateX: this.state.decayValue.x}, // x轴移动
                            {translateY: this.state.decayValue.y}, // y轴移动
                        ]
                    }}
                >
                    <Image ref="image" style={{width:100,height:150}}
                           source={{uri:'beauty.jpg'}}>
                    </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>
        );
    }
}
3.gif

4.Animated.parallel()

同时开始一个动画数组里的全部动画。默认情况下,如果有任何一个动画停止了,其余的也会被停止。可以通过stopTogether 选项设置为 false 来取消这种关联,格式如下:
Animated.parallel(Animates<Array>, [conf<Object>]):,conf参数格式:

{
  stopTogether: false
}

第一个参数接受一个元素为动画的数组,通过执行 start() 方法可以并行执行该数组中的所有方法。如果数组中任意动画被中断的话,该数组内对应的全部动画会一起停止,不过我们可以通过第二个(可选)参数 conf 中的 stopTogether 来取消这种牵连特性。

export default class AnimatedParallel extends Component {

    constructor(props) {
        super(props);

        this.state = {
            dogOpacityValue: new Animated.Value(1),
            dogACCValue : new Animated.Value(0)
        };

        this.parallelAnimated = Animated.parallel(
            [
                Animated.timing(
                    this.state.dogOpacityValue,
                    {
                        toValue: 1,
                        duration: 1000,
                    }
                ),
                Animated.timing(
                    this.state.dogACCValue,
                    {
                        toValue: 1,
                        duration: 2000,
                        easing: Easing.linear,
                    }
                ),
            ],
            {
                stopTogether: false
            }
        );
    }

    _startAnimated() {
        this.state.dogOpacityValue.setValue(0);
        this.state.dogACCValue.setValue(0);
        this.parallelAnimated.start();
    }

    render(){

        //透明度
        const dogOpacity = this.state.dogOpacityValue.interpolate({
            inputRange: [0,0.2,0.4,0.6,0.8,1],
            outputRange: [0,1,0,1,0,1]
        });

        //项链上面
        const neckTop = this.state.dogACCValue.interpolate({
            inputRange: [0, 1],
            outputRange: [350, 235]
        });

        //眼镜左边
        const left = this.state.dogACCValue.interpolate({
            inputRange: [0, 1],
            outputRange: [-120, 127]
        });

        //眼镜旋转
        const rotateZ = this.state.dogACCValue.interpolate({
            inputRange: [0, 1],
            outputRange: ['0deg', '360deg']
        });

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

                {/*// 狗头*/}
                <Animated.View
                    style={{
                        width: 375,
                        height: 240,
                        opacity:dogOpacity,
                    }}
                >
                    <Image ref="image" style={{width:375,height:242}}
                           source={require('./dog.jpg')}>
                    </Image>
                </Animated.View>

                {/*// 项链*/}
                <Animated.View
                    style={{
                        width: 250,
                        height: 100,
                        position: 'absolute',
                        top:neckTop,
                        left:93,
                    }}
                >
                    <Image ref="image" style={{width:250,height:100,resizeMode:'stretch'}}
                           source={require('./necklace.jpg')}>
                    </Image>
                </Animated.View>

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

                {/*// 眼镜*/}
                <Animated.View
                    style={{
                        width: 120,
                        height: 25,
                        position: 'absolute',
                        top:160,
                        left:left,
                        transform:[
                            {rotateZ:rotateZ}
                        ],
                    }}
                >
                    <Image ref="image" style={{width:120,height:25,resizeMode:'stretch'}}
                           source={require('./glasses.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>
        );
    }
}
const styles = StyleSheet.create({
    container: {
        flex:1,
        backgroundColor:"#ffffff",
        justifyContent:'flex-start',
        alignItems:'flex-start',
        paddingTop:100,
        width:'100%',
        height:'100%',
    },
    touchStyle: {
        width:200,
        height:100,
        position:'absolute',
        bottom:0,
        left:screenW/2 - 100,
    },
});
4.gif

5.Animated.sequence()

按顺序执行一个动画数组里的动画,等待一个完成后再执行下一个。如果当前的动画被中止,后面的动画则不会继续执行,格式如下:
Animated.sequence(Animates<Array>)

export default class AnimatedSequence extends Component {

    constructor(props) {
        super(props);

        this.state = {
            turnRotateValue: new Animated.Value(0),
            turnShakeValue : new Animated.Value(0),
            macValue : new Animated.Value(0),
        };

        this.sequenceAnimated = Animated.sequence(
            [
                Animated.timing(
                    this.state.turnRotateValue,
                    {
                        toValue: 1,
                        duration: 5000,
                        easing: Easing.in,
                    }
                ),
                Animated.timing(
                    this.state.turnShakeValue,
                    {
                        toValue: 1,
                        duration: 500,
                        easing: Easing.in,
                        delay:300,
                    }
                ),
                Animated.spring(
                    this.state.macValue,
                    {
                        toValue: 1,
                        friction: 3,
                        tension:10,
                    }
                ),
            ]
        );
    }

    _startAnimated() {
        this.sequenceAnimated.start();
    }

    render(){

        //转盘旋转
        const turnRotateZ = this.state.turnRotateValue.interpolate({
            inputRange: [0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1],
            outputRange: [
                '0deg',
                '180deg',
                '360deg',
                '720deg',
                '1080deg',
                '1800deg',
                '2520deg',
                '3060deg',
                '3420deg',
                '3600deg',
                '3690deg',
            ]
        });

        //转盘震动
        const marginLeft = this.state.turnShakeValue.interpolate({
            inputRange: [0,0.2,0.4,0.6,0.8,1],
            outputRange: [0,-40,40,-40,40,0]
        });

        //MacTop
        const macTop = this.state.macValue.interpolate({
            inputRange: [0, 1],
            outputRange: [-200,150]
        });

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

                {/*// 转盘*/}
                <Animated.View
                    style={{
                        width: 300,
                        height: 300,
                        marginLeft:marginLeft,
                        transform:[
                            {rotateZ:turnRotateZ}
                        ],
                    }}
                >
                    <Image ref="image" style={{width:300,height:300}}
                           source={require('./scenery.jpg')}>
                    </Image>
                </Animated.View>

                {/*// mac*/}
                <Animated.View
                    style={{
                        width: 300,
                        height: 204,
                        position: 'absolute',
                        top:macTop,
                        left:screenW / 2 - 150,
                    }}
                >
                    <Image ref="image" style={{width:300,height:204}}
                           source={require('./landscape.jpg')}>
                    </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>
        );
    }
}
const styles = StyleSheet.create({
    container: {
        flex:1,
        width:screenW,
        backgroundColor:"#ffffff",
        justifyContent:'flex-start',
        alignItems:'flex-start',
        paddingTop:100,
        width:'100%',
        height:'100%',
    },
    touchStyle: {
        width:200,
        height:100,
        bottom:0,
        left:screenW/2 - 100,
        marginTop:60,
    },
});
5.gif

6.Animated.stagger()

一个动画数组,传入一个时间参数来设置队列动画间的延迟,即在前一个动画开始之后,隔一段指定时间才开始执行下一个动画里面的动画,并不关心前一个动画是否已经完成,所以有可能会出现同时执行(重叠)的情况,其格式如下:
Animated.stagger(delayTime<Number>, Animates<Array>)
其中 delayTime 为指定的延迟时间(毫秒),第二个和上面两个一样传入一个动画事件数组。

export default class AnimatedStagger extends Component {

    constructor(props) {
        super(props);

        this.state = {
            redValue: new Animated.Value(0),
            blueValue : new Animated.Value(0),
        };

        this.staggerAnimated = Animated.stagger(2000,
            [
                Animated.timing(
                    this.state.redValue,
                    {
                        toValue: 1,
                        duration: 5000,
                        easing: Easing.in,
                    }
                ),
                Animated.timing(
                    this.state.blueValue,
                    {
                        toValue: 1,
                        duration: 5000,
                        easing: Easing.in,
                    }
                ),
            ]
        );
    }

    _startAnimated() {
        this.staggerAnimated.start();
    }

    render(){

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

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

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

                {/*// 红色*/}
                <Animated.View
                    style={{
                        width: 100,
                        height: 100,
                        backgroundColor:'red',
                        marginLeft:redMarginLeft,
                    }}
                >
                </Animated.View>


                {/*// 蓝色*/}
                <Animated.View
                    style={{
                        width: 100,
                        height: 100,
                        backgroundColor:'blue',
                        marginLeft:blueMarginLeft,
                    }}
                >
                </Animated.View>

                <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({
    container: {
        flex:1,
        width:screenW,
        backgroundColor:"#ffffff",
        justifyContent:'flex-start',
        alignItems:'flex-start',
        paddingTop:100,
        width:'100%',
        height:'100%',
    },
    touchStyle: {
        width:200,
        height:100,
        bottom:0,
        left:screenW/2 - 100,
    },
});
6.gif
上一篇 下一篇

猜你喜欢

热点阅读