React Native中的动画

1,211 阅读3分钟

这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战

流畅、有意义的动画对于移动应用用户体验来说是非常重要的。React Native 提供了两个互补的动画系统:用于创建精细的交互控制动画的Animated和用于全局布局动画的LayoutAnimation

Animated

Animated使得开发者可以简洁地实现各种各样的动画和交互方式,并且具备极高的性能。Animated旨在以声明的形式来定义动画的输入与输出,在其中建立一个可配置的变化函数,然后使用start/stop方法来控制动画按顺序执行。 Animated仅封装了 6 个可以动画化的组件:ViewTextImageScrollViewFlatListSectionList,不过你也可以使用Animated.createAnimatedComponent()来封装你自己的组件。

下面是一个在加载时带有淡入动画效果的视图:

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

const LinAnimate = props => {
    const fadeAnim = useRef(new Animated.Value(0)).current // 透明度初始值设为0

    useEffect(() => {
        Animated.timing(
            // 随时间变化而执行动画
            fadeAnim, // 动画中的变量值
            {
                toValue: 1, // 透明度最终变为1,即完全不透明
                duration: 10000 // 让动画持续一段时间
            }
        ).start() // 开始执行动画
    }, [fadeAnim])

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

// 然后你就可以在组件中像使用`View`那样去使用`FadeInView`了
export default () => {
    return (
        <View
            style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}
        >
            <LinAnimate
                style={{
                    width: 250,
                    height: 50,
                    backgroundColor: 'powderblue'
                }}
            >
                <Text style={{ fontSize: 28, textAlign: 'center', margin: 10 }}>
                    Fading in
                </Text>
            </LinAnimate>
        </View>
    )
}

配置动画

动画拥有非常灵活的配置项。自定义的或预定义的 easing函数、延迟、持续时间、衰减系数、弹性常数等都可以在对应类型的动画中进行配置。

Animated提供了多种动画类型,其中最常用的要属Animated.timing()。它可以使用一些预设的easing曲线函数来控制动画值的变化速度,也支持自定义的曲线函数。动画中通常使用easing曲线函数来控制物体的加速或减速变化。

默认情况下timing使用easeInOut曲线,它使动画体逐渐加速到最大然后逐渐减速到停止。你可以通过传递easing参数来指定不同的变化速度,还支持自定义duration持续时间,甚至是动画开始前的delay延迟。

示例:创建了一个 时长 2 秒的动画,在移动目标到最终位置前会稍微往后退一点:

Animated.timing(this.state.xPosition, {
    toValue: 100,
    easing: Easing.back(),
    duration: 2000
}).start()

组合动画

多个动画可以通过parallel(同时执行)、sequence(顺序执行)、staggerdelay来组合使用。它们中的每一个都接受一个要执行的动画数组,并且自动在适当的时候调用start/stop

例如,下面的动画滑行到一个停止点,然后它在平行旋转时弹回:

Animated.sequence([
    // decay, then spring to start and twirl
    Animated.decay(position, {
        // coast to a stop
        velocity: { x: gestureState.vx, y: gestureState.vy }, // velocity from gesture release
        deceleration: 0.997
    }),
    Animated.parallel([
        // after decay, in parallel:
        Animated.spring(position, {
            toValue: { x: 0, y: 0 } // return to start
        }),
        Animated.timing(twirl, {
            // and twirl
            toValue: 360
        })
    ])
]).start() // start the sequence group