動畫 Animated
RN中的動畫在某種程度上可以理解為“屬性動畫”,也就是以某種過渡方式改變組件樣式屬性值(如組件樣式的left值),驅(qū)動組件以動畫的形式發(fā)生變化(位移、形變或轉(zhuǎn)動)
可動畫化的組件:
- View (Animated.View)
- Text (Animated.Text)
- Image (Animated.Image)
- 使用
createAnimatedComponent自定義
三種動畫類型:
- spring 基礎(chǔ)的單次彈跳物理模型
- decay 以一個初始速度開始并且按一定的衰減比逐漸減慢直至停止
- timing 時間和變量線性變化
1.關(guān)聯(lián)屬性的初始化
關(guān)聯(lián)屬性指的是動畫過程中對應變化的屬性,這個屬性的類型是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.與組件關(guān)聯(lián)
用spring實現(xiàn)的動畫
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(); //執(zhí)行動畫
}
render(){
return (
...
<Animated.Image
style={[styles.image,{left: this.state.left1}]}
source={ loadingImage }/>
...
)
}
}

用timing實現(xiàn)的翻轉(zhuǎn)動畫效果
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 //動畫執(zhí)行時間
}).start(); //執(zhí)行動畫
}
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">插值函數(shù)</l>interpolate,它可以接受一個輸入?yún)^(qū)間,然后將其映射到另一個的輸出區(qū)間,如下:</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實現(xiàn)衰減動畫
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,// 起始速度,必填參數(shù)。
deceleration:0.992 //速度衰減比例,默認為0.997。
}).start();
}
render(){
return (
...
<Animated.Image
style={[styles.image,{
left: this.state.decayLeft4
}]}
source={ loadingImage }/>
...
)
}
}

組合畫效果
static sequence(animations: Array<CompositeAnimation>)(接受一個動畫數(shù)組,<b style="color: red">依次</b>執(zhí)行數(shù)組里的動畫)-
static parallel(animations: Array<CompositeAnimation>, config?: ParallelConfig)(接受一個動畫數(shù)組,<b style="color: red">同時</b>執(zhí)行數(shù)組里的動畫)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() { //串行執(zhí)行 Animated.sequence([ // 并行執(zhí)行(滾動,同時旋轉(zhuǎn)) Animated.parallel([ Animated.timing(this.state.left3, { toValue: 1, duration: 3000, }), Animated.timing(this.state.rotation3, { toValue: 1, duration: 1000, }), ]), // 滾動、旋轉(zhuǎn)結(jié)束 執(zhí)行縮放 Animated.timing(this.state.scale3, { toValue: 1, duration: 500, }) ]).start() //執(zhí)行動畫 } 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 執(zhí)行串行的動畫數(shù)組中
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后執(zhí)行
Animated.delay(1000),
Animated.timing(this.state.left5, {
toValue: 100,// 起始速度,必填參數(shù)。
duration: 1000
})
]).start()
}
render(){
return (
...
<Animated.Image
style={[styles.image,{
left: this.state.left5
}]}
source={ loadingImage }/>
...
)
}
}

