文档
https://reactnative.cn/docs/animated
简单使用
const App = () => {
// fadeAnim will be used as the value for opacity. Initial Value: 0
const fadeAnim = useRef(new Animated.Value(0)).current;
const fadeIn = () => {
// Will change fadeAnim value to 1 in 5 seconds
Animated.timing(fadeAnim, {
toValue: 1,
duration: 5000,
useNativeDriver: true,
}).start();
};
const fadeOut = () => {
// Will change fadeAnim value to 0 in 3 seconds
Animated.timing(fadeAnim, {
toValue: 0,
duration: 3000,
useNativeDriver: true,
}).start();
};
return (
<SafeAreaView style={styles.container}>
<Animated.View
style={[
styles.fadingContainer,
{
// Bind opacity to animated value
opacity: fadeAnim,
},
]}>
<Text style={styles.fadingText}>Fading View!</Text>
</Animated.View>
<View style={styles.buttonRow}>
<Button title="Fade In View" onPress={fadeIn} />
<Button title="Fade Out View" onPress={fadeOut} />
</View>
</SafeAreaView>
);
};
配置动画
Animated
提供了三种动画类型。每种动画类型都提供了特定的函数曲线,用于控制动画值从初始值变化到最终值的变化过程:
-
Animated.decay()
以指定的初始速度开始变化,然后变化速度越来越慢直至停下。 -
Animated.spring()
提供了一个基础的弹簧物理模型. -
Animated.timing()
使用easing 函数让数值随时间动起来。
大多数情况下你应该使用timing()
。默认情况下,它使用对称的 easeInOut 曲线,将对象逐渐加速到全速,然后通过逐渐减速停止结束。
使用动画
通过在动画上调用start()
来启动动画。 start()
可以传入一个回调函数,以便在动画完成时得到通知调用。如果动画运行正常,则完成回调收到的值为{finished:true}
。如果动画是因为调用了stop()
而结束(例如,因为它被手势或其他动画中断),则它会收到{finished:false}
。
Animated.timing({}).start(({finished}) => { /* 动画完成的回调函数 */});
启用原生动画驱动
使用原生动画,我们会在开始动画之前将所有关于动画的内容发送到原生代码,从而使用原生代码在 UI 线程上执行动画,而不是通过对每一帧的桥接去执行动画。一旦动画开始,JS 线程就可以在不影响动画效果的情况下阻塞(去执行其他任务)掉了。
您可以通过在动画配置中指定useNativeDriver:true
来使用原生动画驱动。你可以在动画文档 中看到更详细的解释。
自定义动画组件
组件必须经过特殊处理才能用于动画。所谓的特殊处理主要是指把动画值绑定到属性上,并且在一帧帧执行动画时避免 react 重新渲染和重新调和的开销。此外还得在组件卸载时做一些清理工作,使得这些组件在使用时是安全的。
-
createAnimatedComponent()
方法正是用来处理组件,使其可以用于动画。
Animated
中默认导出了以下这些可以直接使用的动画组件,当然它们都是通过使用上面这个方法进行了封装:
Animated.Image
Animated.ScrollView
Animated.Text
Animated.View
Animated.FlatList
Animated.SectionList
组合动画
动画还可以使用组合函数以复杂的方式进行组合:
-
Animated.delay()
在给定延迟后开始动画。 -
Animated.parallel()
同时启动多个动画。 -
Animated.sequence()
按顺序启动动画,等待每一个动画完成后再开始下一个动画。 -
Animated.stagger()
按照给定的延时间隔,顺序并行的启动动画。
动画也可以通过将toValue
设置为另一个动画的Animated.Value
来简单的链接在一起。请参阅动画指南中的跟踪动态值值。
默认情况下,如果一个动画停止或中断,则组合中的所有其他动画也会停止。
合成动画值
你可以使用加减乘除以及取余等运算来把两个动画值合成为一个新的动画值:
插值
interpolate()
函数允许输入范围映射到不同的输出范围。默认情况下,它将推断超出给定范围的曲线,但也可以限制输出值。它默认使用线性插值,但也支持缓动功能。
你可以在动画文档中了解到更多。
所有动画值都可以执行插值(interpolation)操作。插值是指将一定范围的输入值映射到另一组不同的输出值,一般我们使用线性的映射,但是也可以使用 easing 函数。默认情况下,它会将曲线外推到给定范围之外,但您也可以让它限制为输出值。
一个简单的将范围 0-1 转换为范围 0-100 的映射操作是:
value.interpolate({ inputRange: [0, 1], outputRange: [0, 100]});
例如,你可能想通过使用 Animated.Value
的值从 0 变化到 1 来让 position
从 150px 变化到 0px,同时 opacity
从 0 变为 1。这一点可以通过将 style
从 example 修改为下面的样子来实现:
style={{ opacity: this.state.fadeAnim, // Binds directly transform: [{ translateY: this.state.fadeAnim.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]});
它的最终映射结果如下:
| 输入 | 输出 || ---- | ---- || -400 | 450 || -300 | 300 || -200 | 150 || -100 | 0 || -50 | 0.5 || 0 | 1 || 50 | 0.5 || 100 | 0 || 101 | 0 || 200 | 0 |
interpolate()
还支持到字符串的映射,从而可以实现颜色以及带有单位的值的动画变换。例如你可以像下面这样实现一个旋转动画:
value.interpolate({ inputRange: [0, 360], outputRange: ['0deg', '360deg']});
interpolate()
还支持任意的渐变函数,其中有很多已经在Easing
类中定义了,包括二次、指数、贝塞尔等曲线以及 step、bounce 等方法。interpolation
还支持限制输出区间outputRange
。你可以通过设置extrapolate
、extrapolateLeft
或extrapolateRight
属性来限制输出区间。默认值是extend
(允许超出),不过你可以使用clamp
选项来阻止输出值超过outputRange
。
跟踪动态值
动画中所设的值还可以通过跟踪别的值得到。你只要把 toValue 设置成另一个动态值而不是一个普通数字就行了。比如我们可以用弹跳动画来实现聊天头像的闪动,又比如通过timing
设置duration:0
来实现快速的跟随。他们还可以使用插值来进行组合:
Animated.spring(follower, { toValue: leader }).start();Animated.timing(opacity, { toValue: pan.x.interpolate({ inputRange: [0, 300], outputRange: [1, 0] })}).start();
变量 leader
和 follower
通过 Animated.ValueXY()
来定义。这是一个方便的处理 2D 交互的办法,譬如旋转或拖拽。它是一个简单的包含了两个Animated.Value
实例的包装,然后提供了一系列辅助函数,使得ValueXY
在许多时候可以替代Value
来使用。比如在上面的代码片段中,leader
和follower
可以同时为valueXY
类型,这样 x 和 y 的值都会被跟踪。
网友评论