【搭建react-native项目框架】4.自定义TabBar中间按钮,实现播放时旋转动画
扫描二维码
随时随地手机看文章
关于如何集成TabBar,请看上一节《【搭建react-native项目框架】3.集成第三方路由和tab页》
本节只讲解如何自定义TabBar的中间按钮,以及播放时旋转动画的实现。
关于动画与播放器的集成可以参考https://github.com/pheromone/react-native-videoDemo,但这个项目目前安卓存在bug,所以我只借鉴了动画部分。
还是先来看效果图
2.悬浮效果可以用绝对定位来实现,见下图
在components下新建一个playButton.js文件。先写一个外层View,绝对定位到页面底部中间位置;再做个带边框的圆形View;然后用长方形View将圆形View下半部的边框覆盖;最后写个旋转图和按钮。
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.实现旋转动画。先构造初始旋转角度、播放状态和旋转动画
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.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";
//页面
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 (
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',
},
});