最近,UI设计师调整了登录页面的交互,需要实现:
没勾选协议点灰色登录按钮,则左右抖动两次后出现橙色提示,勾选后橙色提示消失。UI设计图:

提示问题不难解决,这里就略过了,重点讲一下如何实现左右抖动两次。
由于项目使用的是 React Native,考虑使用 Animated 来实现。
AnimatedAnimated 是 React Native 中的一个库,旨在使动画变得流畅,强大并易于构建和维护。
侧重于输入和输出之间的声明性关系,以及两者之间的可配置变换,此外还提供了简单的 start/stop 方法来控制基于时间的动画执行。
参考官方文档后,需要用到的 api 有:
static timing(value, config)
推动一个值按照一个缓动曲线而随时间变化。Easing 模块定义了一大堆曲线,你也可以使用你自己的函数。
Config 参数有以下这些属性:
duration: 动画的持续时间(毫秒)。默认值为 500.easing: 缓动函数。 默认为 Easing.inOut(Easing.ease)。delay: 开始动画前的延迟时间(毫秒)。默认为 0.isInteraction: 指定本动画是否在 InteractionManager 的队列中注册以影响其任务调度。默认值为 true。useNativeDriver: 启用原生动画驱动。默认不启用(false)。static parallel(animations, config?)
同时开始一个动画数组里的全部动画。默认情况下,如果有任何一个动画停止了,其余的也会被停止。你可以通过 stopTogether 选项来改变这个效果。
Animated.Value,将它连接到动画组件的一个或多个样式属性;这里是连接到两个属性(marginLeft,marginRight)上,因为要左右抖动。
对应代码:
constructor(props) {
super(props);
this.state = {
left: new Animated.Value(0), // 初始值
right: new Animated.Value(0) // 初始值
}
}
Animated.timing() 通过动画效果展示数据的变化。要实现左右抖动两次,需要使用 Animated.parallel() ——多个动画同时开始。
import {
Animated,
Easing
} from 'react-native';
Animated.parallel([
Animated.timing(this.state.left, {
toValue: 50,
duration: 20,
easing: Easing.inOut(Easing.elastic(1))
}),
Animated.timing(this.state.right, {
toValue: 50,
duration: 100,
easing: Easing.inOut(Easing.elastic(1))
}),
Animated.timing(this.state.left, {
toValue: 50,
duration: 120,
easing: Easing.inOut(Easing.elastic(1))
}),
Animated.timing(this.state.right, {
toValue: 50,
duration: 200,
easing: Easing.inOut(Easing.elastic(1))
})
]).start(({ finished }) => {
/* 动画完成的回调函数 */
console.log('Animated.parallel-----动画完成收到的回调-----finished :>> ', finished);
this.setState({
left: new Animated.Value(0),
right: new Animated.Value(0)
})
})
组件必须经过特殊处理才能用于动画。所谓的特殊处理主要是指把动画值绑定到属性上,并且在一帧帧执行动画时避免 react 重新渲染和重新调和的开销。此外还得在组件卸载时做一些清理工作,使得这些组件在使用时是安全的。
Animated 中默认导出了以下这些可以直接使用的动画组件,当然它们都是通过使用上面这个方法进行了封装:
Animated.ImageAnimated.ScrollViewAnimated.TextAnimated.ViewAnimated.FlatListAnimated.SectionList示例代码:
import {
Animated,
Text,
StyleSheet
} from 'react-native';
<Animated.View style={[styles.container, { marginLeft: this.state.left, marginRight: this.state.right }]}>
<Text style={styles.agree}>{'用户协议'}</Text>
</Animated.View>
到这里一开始的需求就实现了。当然,如何触发动画需要根据需求来,触发方法放在合适的位置上