动画 Animated
RN中的动画在某种程度上可以理解为“属性动画”,也就是以某种过渡方式改变组件样式属性值(如组件样式的left值),驱动组件以动画的形式发生变化(位移、形变或转动)
可动画化的组件:
- View (Animated.View)
- Text (Animated.Text)
- Image (Animated.Image)
- 使用
createAnimatedComponent
自定义
三种动画类型:
- spring 基础的单次弹跳物理模型
- decay 以一个初始速度开始并且按一定的衰减比逐渐减慢直至停止
- timing 时间和变量线性变化
1.关联属性的初始化
关联属性指的是动画过程中对应变化的属性,这个属性的类型是Animated.Value
,可以通过new Animated.Value()
、new Animated.ValueXY()
(处理2D动画)等方法初始化,如下:
class PlaygroundContainer extends Component {
constructor(props) {
super(props);
this.state = {
left1: new Animated.Value(0),
rotation2: new Animated.Value(0),
pan: new Animated.Value({x:0, y:0})
}
}
...
}
2.与组件关联
用spring实现的动画
import loadingImage from '../../assets/0.gif'
...
class PlaygroundContainer extends Component {
constructor(props) {
super(props);
this.state = {
left1: new Animated.Value(0),
}
}
componentDidMount() {
Animated.spring(this.state.left1, {
toValue: 100, //属性目标值
friction: 1, //摩擦力 (越小 振幅越大)
tension: 100, //拉力
}).start(); //执行动画
}
render(){
return (
...
<Animated.Image
style={[styles.image,{left: this.state.left1}]}
source={ loadingImage }/>
...
)
}
}
用timing实现的翻转动画效果
import loadingImage from '../../assets/0.gif'
...
class PlaygroundContainer extends Component {
constructor(props) {
super(props);
this.state = {
rotation2: new Animated.Value(0),
}
}
componentDidMount() {
Animated.timing(this.state.rotation2, {
toValue: 1, //属性目标值
duration: 3000 //动画执行时间
}).start(); //执行动画
}
render(){
return (
...
<Animated.Image
style={[styles.image,{
transform:[
{
rotateX: this.state.rotation2.interpolate({
inputRange:[0,1],
outputRange:['0deg','360deg']
})
}
]
}]}
source={ loadingImage }/>
...
)
}
}
<b> 这里用到<l style="color:red">插值函数</l>interpolate
,它可以接受一个输入区间,然后将其映射到另一个的输出区间,如下:</b>
{
rotateX: this.state.rotation2.interpolate({
inputRange:[0,1],
outputRange:['0deg','360deg']
})
}
通过映射,
rotation2的value | 映射输出 |
---|---|
0 | 0° |
0.2 | 72° |
0.5 | 180° |
1 | 360° |
用decay实现衰减动画
import loadingImage from '../../assets/0.gif'
...
class PlaygroundContainer extends Component {
constructor(props) {
super(props);
this.state = {
decayLeft4: new Animated.Value(0),
}
}
componentDidMount() {
Animated.decay(this.state.decayLeft4, {
velocity: 2,// 起始速度,必填参数。
deceleration:0.992 //速度衰减比例,默认为0.997。
}).start();
}
render(){
return (
...
<Animated.Image
style={[styles.image,{
left: this.state.decayLeft4
}]}
source={ loadingImage }/>
...
)
}
}
组合画效果
static sequence(animations: Array<CompositeAnimation>)
(接受一个动画数组,<b style="color: red">依次</b>执行数组里的动画)-
static parallel(animations: Array<CompositeAnimation>, config?: ParallelConfig)
(接受一个动画数组,<b style="color: red">同时</b>执行数组里的动画)import loadingImage from '../../assets/0.gif' ... class PlaygroundContainer extends Component { constructor(props) { super(props); this.state = { left3: new Animated.Value(0), rotation3: new Animated.Value(0), scale3: new Animated.Value(0.5), } } componentDidMount() { //串行执行 Animated.sequence([ // 并行执行(滚动,同时旋转) Animated.parallel([ Animated.timing(this.state.left3, { toValue: 1, duration: 3000, }), Animated.timing(this.state.rotation3, { toValue: 1, duration: 1000, }), ]), // 滚动、旋转结束 执行缩放 Animated.timing(this.state.scale3, { toValue: 1, duration: 500, }) ]).start() //执行动画 } render(){ return ( ... <Animated.Image style={[styles.image,{ left: this.state.left3.interpolate({ inputRange:[0,1], outputRange:[0, width - 100] }), transform:[ {rotateZ: this.state.rotation3.interpolate({ inputRange:[0,1], outputRange:['0deg','360deg']}) }, {rotateX: this.state.rotation3.interpolate({ inputRange:[0,1], outputRange:['0deg','360deg']}) }, {scale: this.state.scale3} ] }]} source={ loadingImage }/> ... ) } }
用delay做延时动画
Animated.delay(1000)
延时1000ms
把delay
动画放进sequence
执行串行的动画数组中
import loadingImage from '../../assets/0.gif'
...
class PlaygroundContainer extends Component {
constructor(props) {
super(props);
this.state = {
left5: new Animated.Value(0),
}
}
componentDidMount() {
Animated.sequence([
// 1000 ms后执行
Animated.delay(1000),
Animated.timing(this.state.left5, {
toValue: 100,// 起始速度,必填参数。
duration: 1000
})
]).start()
}
render(){
return (
...
<Animated.Image
style={[styles.image,{
left: this.state.left5
}]}
source={ loadingImage }/>
...
)
}
}