【搭建react-native項(xiàng)目框架】4.自定義TabBar中間按鈕,實(shí)現(xiàn)播放時(shí)旋轉(zhuǎn)動(dòng)畫(huà)
關(guān)于如何集成TabBar,請(qǐng)看上一節(jié)《【搭建react-native項(xiàng)目框架】3.集成第三方路由和tab頁(yè)》
本節(jié)只講解如何自定義TabBar的中間按鈕,以及播放時(shí)旋轉(zhuǎn)動(dòng)畫(huà)的實(shí)現(xiàn)。
關(guān)于動(dòng)畫(huà)與播放器的集成可以參考https://github.com/pheromone/react-native-videoDemo,但這個(gè)項(xiàng)目目前安卓存在bug,所以我只借鑒了動(dòng)畫(huà)部分。
還是先來(lái)看效果圖
2.懸浮效果可以用絕對(duì)定位來(lái)實(shí)現(xiàn),見(jiàn)下圖
在components下新建一個(gè)playButton.js文件。先寫(xiě)一個(gè)外層View,絕對(duì)定位到頁(yè)面底部中間位置;再做個(gè)帶邊框的圓形View;然后用長(zhǎng)方形View將圓形View下半部的邊框覆蓋;最后寫(xiě)個(gè)旋轉(zhuǎn)圖和按鈕。
this.play()} underlayColor="transparent" style={[styles.playInner]}>
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.實(shí)現(xiàn)旋轉(zhuǎn)動(dòng)畫(huà)。先構(gòu)造初始旋轉(zhuǎn)角度、播放狀態(tài)和旋轉(zhuǎn)動(dòng)畫(huà)
this.state = {
playImage: require('./resources/images/play.png'),
rotateValue: new Animated.Value(0), //旋轉(zhuǎn)角度的初始值
};
this.isPlaying = false;
this.playerAnimated = Animated.timing(this.state.rotateValue, {
toValue: 1, //角度從0變1
duration: 15000, //從0到1的時(shí)間
easing: Easing.inOut(Easing.linear), //線性變化,勻速旋轉(zhuǎn)
});
根據(jù)播放狀態(tài)切換播放按鈕的圖標(biāo),并開(kāi)始/暫停播放
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();
}
}
開(kāi)始播放
startPlay() {
this.playerAnimated.start(() => {
this.playerAnimated = Animated.timing(this.state.rotateValue, {
toValue: 1, //角度從0變1
duration: 15000, //從0到1的時(shí)間
easing: Easing.inOut(Easing.linear), //線性變化,勻速旋轉(zhuǎn)
});
this.rotating();
});
}
暫停播放
stopPlay() {
this.state.rotateValue.stopAnimation((oneTimeRotate) => {
//計(jì)算角度比例
this.playerAnimated = Animated.timing(this.state.rotateValue, {
toValue: 1,
duration: (1-oneTimeRotate) * 15000,
easing: Easing.inOut(Easing.linear),
});
});
}
開(kāi)始旋轉(zhuǎn)動(dòng)畫(huà)
rotating() {
if (this.isPlaying) {
this.state.rotateValue.setValue(0);
this.playerAnimated.start(() => {
this.rotating()
})
}
};
4.在App.js文件中引入playButton.jsimport PlayButton from "./components/playButton";
在最外層View組件底部渲染PlayButton
//Router......
import React, { Component } from 'react';
import {
Animated,
Easing,
StyleSheet,
View,
TouchableOpacity,
Image,
} from "react-native";
//自定義組件
import Common from "./common";
//頁(yè)面
import PlayScreen from '../views/play'; //播放頁(yè)
export default class PlayButton extends Component {
constructor(props) {
super(props);
//使用Animated.Value設(shè)定初始化值(角度)
this.state = {
playImage: require('../resources/images/play.png'),
rotateValue: new Animated.Value(0), //旋轉(zhuǎn)角度的初始值
};
this.isPlaying = false;
this.playerAnimated = Animated.timing(this.state.rotateValue, {
toValue: 1, //角度從0變1
duration: 15000, //從0到1的時(shí)間
easing: Easing.inOut(Easing.linear), //線性變化,勻速旋轉(zhuǎn)
});
}
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的時(shí)間
easing: Easing.inOut(Easing.linear), //線性變化,勻速旋轉(zhuǎn)
});
this.rotating();
});
}
stopPlay() {
this.state.rotateValue.stopAnimation((oneTimeRotate) => {
//計(jì)算角度比例
this.playerAnimated = Animated.timing(this.state.rotateValue, {
toValue: 1,
duration: (1-oneTimeRotate) * 15000,
easing: Easing.inOut(Easing.linear),
});
});
}
render() {
return (
this.play()} underlayColor="transparent" style={[styles.playInner]}>
);
}
}
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',
},
});