【搭建react-native專案框架】4.自定義TabBar中間按鈕,實現播放時旋轉動畫
阿新 • • 發佈:2019-02-13
本節只講解如何自定義TabBar的中間按鈕,以及播放時旋轉動畫的實現。
還是先來看效果圖
其實思路很簡單,首先要使TabBar把中間按鈕的位置空出來,然後擺上一個懸浮的按鈕,就能實現中間按鈕了。
1.設定CustomTabBar的placeMiddle屬性為true,這個屬性表示是否把中間按鈕的位置留出來。
<CustomTabBar tabNames={tabNames} //tab名稱 placeMiddle={true} //中間是否佔位,即中間是否需要用特殊按鈕樣式等 />
2.懸浮效果可以用絕對定位來實現,見下圖
在components下新建一個playButton.js檔案。先寫一個外層View,絕對定位到頁面底部中間位置;再做個帶邊框的圓形View;然後用長方形View將圓形View下半部的邊框覆蓋;最後寫個旋轉圖和按鈕。
<View style={[styles.playBox]}> <View style={[styles.playBoxCircle]} /> <View style={[styles.playBoxBackground]} /> <TouchableOpacity onPress={() => this.play()} underlayColor="transparent" style={[styles.playInner]}> <View style={[styles.playInnerBox]}> <Animated.Image source={require('./resources/images/src/miss.jpg')} style={[styles.playBackImage, { transform: [ //使用interpolate插值函式,實現了從數值單位的對映轉換,上面角度從0到1,這裡把它變成0-360的變化 {rotateZ: this.state.rotateValue.interpolate({ inputRange: [0,1], outputRange: ['0deg', '360deg'], })}, ] }]} /> <Image source={this.state.playImage} style={[{width: Common.autoScaleSize(32), height: Common.autoScaleSize(32)}]} /> </View> </TouchableOpacity> </View>
const styles = StyleSheet.create({ playBox: { width: Common.autoScaleSize(128), height: Common.autoScaleSize(136), position: 'absolute', bottom: 0, left: Common.autoScaleSize(311), flexDirection: 'column', justifyContent: 'flex-start', alignItems: 'center', }, playBoxCircle: { backgroundColor: '#ffffff', width: Common.autoScaleSize(128), height: Common.autoScaleSize(128), borderRadius: Common.autoScaleSize(128), position: 'absolute', bottom: Common.autoScaleSize(8), borderWidth: Common.autoScaleSize(1), borderColor: '#cdcdcd', }, playBoxBackground: { backgroundColor: '#ffffff', width: Common.autoScaleSize(125), height: Common.autoScaleSize(72), position: 'absolute', bottom: 0, left: Common.autoScaleSize(1), }, playInner: { width: Common.autoScaleSize(101), height: Common.autoScaleSize(101), borderRadius: Common.autoScaleSize(101), position: 'absolute', bottom: Common.autoScaleSize(20), flexDirection: 'column', justifyContent: 'center', alignItems: 'center', }, playInnerBox: { backgroundColor: '#cdcdcd', width: Common.autoScaleSize(101), height: Common.autoScaleSize(101), borderRadius: Common.autoScaleSize(101), flexDirection: 'column', justifyContent: 'center', alignItems: 'center', }, playBackImage: { width: Common.autoScaleSize(101), height: Common.autoScaleSize(101), borderRadius: Common.autoScaleSize(101), position: 'absolute', }, });
3.實現旋轉動畫。
先構造初始旋轉角度、播放狀態和旋轉動畫
this.state = {
playImage: require('./resources/images/play.png'),
rotateValue: new Animated.Value(0), //旋轉角度的初始值
};
this.isPlaying = false;
this.playerAnimated = Animated.timing(this.state.rotateValue, {
toValue: 1, //角度從0變1
duration: 15000, //從0到1的時間
easing: Easing.inOut(Easing.linear), //線性變化,勻速旋轉
});
根據播放狀態切換播放按鈕的圖示,並開始/暫停播放
play() {
this.isPlaying = !this.isPlaying;
if (this.isPlaying === true) {
this.setState({
playImage: require('./resources/images/pause.png'),
});
this.startPlay();
} else {
this.setState({
playImage: require('./resources/images/play.png'),
});
this.stopPlay();
}
}
開始播放
startPlay() {
this.playerAnimated.start(() => {
this.playerAnimated = Animated.timing(this.state.rotateValue, {
toValue: 1, //角度從0變1
duration: 15000, //從0到1的時間
easing: Easing.inOut(Easing.linear), //線性變化,勻速旋轉
});
this.rotating();
});
}
暫停播放
stopPlay() {
this.state.rotateValue.stopAnimation((oneTimeRotate) => {
//計算角度比例
this.playerAnimated = Animated.timing(this.state.rotateValue, {
toValue: 1,
duration: (1-oneTimeRotate) * 15000,
easing: Easing.inOut(Easing.linear),
});
});
}
開始旋轉動畫
rotating() {
if (this.isPlaying) {
this.state.rotateValue.setValue(0);
this.playerAnimated.start(() => {
this.rotating()
})
}
};
4.在App.js檔案中引入playButton.js
import PlayButton from "./components/playButton";
在最外層View元件底部渲染PlayButton
<View style={[{flex: 1}]}>
//Router......
<PlayButton />
</View>
最後上完整的playButton.js程式碼
import React, { Component } from 'react';
import {
Animated,
Easing,
StyleSheet,
View,
TouchableOpacity,
Image,
} from "react-native";
//自定義元件
import Common from "./common";
//頁面
import PlayScreen from '../views/play'; //播放頁
export default class PlayButton extends Component {
constructor(props) {
super(props);
//使用Animated.Value設定初始化值(角度)
this.state = {
playImage: require('../resources/images/play.png'),
rotateValue: new Animated.Value(0), //旋轉角度的初始值
};
this.isPlaying = false;
this.playerAnimated = Animated.timing(this.state.rotateValue, {
toValue: 1, //角度從0變1
duration: 15000, //從0到1的時間
easing: Easing.inOut(Easing.linear), //線性變化,勻速旋轉
});
}
play() {
this.isPlaying = !this.isPlaying;
if (this.isPlaying === true) {
this.setState({
playImage: require('../resources/images/pause.png'),
});
this.startPlay();
} else {
this.setState({
playImage: require('../resources/images/play.png'),
});
this.stopPlay();
}
}
rotating() {
if (this.isPlaying) {
this.state.rotateValue.setValue(0);
this.playerAnimated.start(() => {
this.rotating()
})
}
};
startPlay() {
this.playerAnimated.start(() => {
this.playerAnimated = Animated.timing(this.state.rotateValue, {
toValue: 1, //角度從0變1
duration: 15000, //從0到1的時間
easing: Easing.inOut(Easing.linear), //線性變化,勻速旋轉
});
this.rotating();
});
}
stopPlay() {
this.state.rotateValue.stopAnimation((oneTimeRotate) => {
//計算角度比例
this.playerAnimated = Animated.timing(this.state.rotateValue, {
toValue: 1,
duration: (1-oneTimeRotate) * 15000,
easing: Easing.inOut(Easing.linear),
});
});
}
render() {
return (
<View style={[styles.playBox]}>
<View style={[styles.playBoxCircle]} />
<View style={[styles.playBoxBackground]} />
<TouchableOpacity onPress={() => this.play()} underlayColor="transparent" style={[styles.playInner]}>
<View style={[styles.playInnerBox]}>
<Animated.Image
source={require('../resources/images/src/miss.jpg')}
style={[styles.playBackImage, {
transform: [
//使用interpolate插值函式,實現了從數值單位的對映轉換,上面角度從0到1,這裡把它變成0-360的變化
{rotateZ: this.state.rotateValue.interpolate({
inputRange: [0,1],
outputRange: ['0deg', '360deg'],
})},
]
}]}
/>
<Image
source={this.state.playImage}
style={[{width: Common.autoScaleSize(32), height: Common.autoScaleSize(32)}]}
/>
</View>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
playBox: {
width: Common.autoScaleSize(128),
height: Common.autoScaleSize(136),
position: 'absolute',
bottom: 0,
left: Common.autoScaleSize(311),
flexDirection: 'column',
justifyContent: 'flex-start',
alignItems: 'center',
},
playBoxCircle: {
backgroundColor: '#ffffff',
width: Common.autoScaleSize(128),
height: Common.autoScaleSize(128),
borderRadius: Common.autoScaleSize(128),
position: 'absolute',
bottom: Common.autoScaleSize(8),
borderWidth: Common.autoScaleSize(1),
borderColor: '#cdcdcd',
},
playBoxBackground: {
backgroundColor: '#ffffff',
width: Common.autoScaleSize(128),
height: Common.autoScaleSize(101),
position: 'absolute',
bottom: 0,
},
playInner: {
width: Common.autoScaleSize(101),
height: Common.autoScaleSize(101),
borderRadius: Common.autoScaleSize(101),
position: 'absolute',
bottom: Common.autoScaleSize(20),
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
},
playInnerBox: {
backgroundColor: '#cdcdcd',
width: Common.autoScaleSize(101),
height: Common.autoScaleSize(101),
borderRadius: Common.autoScaleSize(101),
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
},
playBackImage: {
width: Common.autoScaleSize(101),
height: Common.autoScaleSize(101),
borderRadius: Common.autoScaleSize(101),
position: 'absolute',
},
});