这篇文章主要跟大家分享一个视频播放的react-native的工具,以及不是使用Orientation库,进行控制视频播放
效果如下:
[链接](https://s23.aconvert.com/convert/p3r68-cdx67/9w9i3-vht6k.gif](https://s23.aconvert.com/convert/p3r68-cdx67/9w9i3-vht6k.gif)
1,集成react-native-video
传送门https://github.com/react-native-community/react-native-video#ios-app-transport-security
npm install --save react-native-video
react-native link react-native-video
2,封装播放组件
针对于播放组件
定义变量:
state = {
data: {},
videoUrl:
"http://124.129.157.208:8810/SD/2017qingdao/xiaoxueEnglish/grade3/b/1.mp4",
videoCover:
"http://124.129.157.208:8889/data/uploads/kecheng/2018/01/18/5a600b2c99836.png@0o_0l_220w.png",
videoHeight: (screenWidth * 9) / 16.0, // 默认16:9的宽高比
videoWidth: screenWidth,
showVideoCover: true, // 是否显示视频封面
showVideoControl: false, // 是否显示视频控制组件
isPlaying: false, // 视频是否正在播放
currentTime: 0, // 视频当前播放的时间
duration: 0, // 视频的总时长
isFullScreen: false, // 当前是否全屏显示
playFromBeginning: false, // 是否从头开始播放
isShowToolBar: true,
};
控制安卓物理返回键,防止横屏退出,页面一直横屏
componentWillMount() {
if (!CommonUtils.ios) {
BackHandler.addEventListener("hardwareBackPress", this.onBackAnd);
}
}
componentWillUnmount() {
if (!CommonUtils.ios) {
BackHandler.removeEventListener("hardwareBackPress", this.onBackAnd);
}
}
onBackAnd = () => {
if (this.state.isFullScreen) {
NativeModules.DeviceOrientation.orientation("left");
this.setState({
isShowToolBar: true,
});
} else {
this.props.navigation.goBack();
}
};
Video组件回调事件
onLoadStart = () => {
console.log("视频开始加载");
};
onBuffering = () => {
console.log("视频缓冲中...");
};
onLoaded = data => {
console.log("视频加载完成");
this.setState({
duration: data.duration
});
};
onProgressChanged = data => {
console.log("视频进度更新");
if (this.state.isPlaying) {
this.setState({
currentTime: data.currentTime
});
}
};
onPlayEnd = () => {
console.log("视频播放结束");
this.setState({
currentTime: 0,
isPlaying: false,
playFromBeginning: true
});
};
onPlayError = () => {
console.log("视频播放失败");
};
控件点击事件
/// 控制播放器工具栏的显示和隐藏
hideControl() {
if (this.state.showVideoControl) {
this.setState({
showVideoControl: false
});
} else {
this.setState(
{
showVideoControl: true
},
// 5秒后自动隐藏工具栏
() => {
setTimeout(() => {
this.setState({
showVideoControl: false
});
}, 5000);
}
);
}
}
/// 点击了播放器正中间的播放按钮
onPressPlayButton() {
let isPlay = !this.state.isPlaying;
this.setState({
isPlaying: isPlay,
showVideoCover: false
});
if (this.state.playFromBeginning) {
this.videoPlayer.seek(0);
this.setState({
playFromBeginning: false
});
}
}
/// 点击了工具栏上的播放按钮
onControlPlayPress() {
this.onPressPlayButton();
}
/// 点击了工具栏上的全屏按钮
onControlShrinkPress() {
if (this.state.isFullScreen) {
// Orientation.lockToPortrait();
NativeModules.DeviceOrientation.orientation("left");
this.setState({
isShowToolBar: true,
});
} else {
// Orientation.lockToLandscape();
NativeModules.DeviceOrientation.orientation("right");
this.setState({
isShowToolBar: false,
});
}
}
/// 进度条值改变
onSliderValueChanged(currentTime) {
this.videoPlayer.seek(currentTime);
if (this.state.isPlaying) {
this.setState({
currentTime: currentTime
});
} else {
this.setState({
currentTime: currentTime,
isPlaying: true,
showVideoCover: false
});
}
}
/// 屏幕旋转时宽高会发生变化,可以在onLayout的方法中做处理,比监听屏幕旋转更加及时获取宽高变化
onLayout = event => {
//获取根View的宽高
let { width, height } = event.nativeEvent.layout;
console.log("通过onLayout得到的宽度:" + width);
console.log("通过onLayout得到的高度:" + height);
// 一般设备横屏下都是宽大于高,这里可以用这个来判断横竖屏
let isLandscape = width > height;
if (isLandscape) {
this.setState({
videoWidth: width,
videoHeight: height,
isFullScreen: true
});
} else {
this.setState({
videoWidth: width,
videoHeight: (width * 9) / 16,
isFullScreen: false
});
}
// Orientation.unlockAllOrientations();
};
/// -------外部调用事件方法-------
///播放视频,提供给外部调用
playVideo() {
this.setState({
isPlaying: true,
showVideoCover: false
});
}
/// 暂停播放,提供给外部调用
pauseVideo() {
this.setState({
isPlaying: false
});
}
/// 切换视频并可以指定视频开始播放的时间,提供给外部调用
switchVideo(videoURL, seekTime) {
this.setState({
videoUrl: videoURL,
currentTime: seekTime,
isPlaying: true,
showVideoCover: false
});
this.videoPlayer.seek(seekTime);
}
加载视频组件代码:
render() {
return (
<View style={styles.container} onLayout={this.onLayout}>
<View
style={{
width: this.state.videoWidth,
height: this.state.videoHeight,
backgroundColor: "#000000"
}}
>
<Video
ref={ref => (this.videoPlayer = ref)}
source={{ uri: this.state.videoUrl }}
rate={1.0}
volume={1.0}
muted={false}
paused={!this.state.isPlaying}
resizeMode={"contain"}
playWhenInactive={false}
playInBackground={false}
ignoreSilentSwitch={"ignore"}
progressUpdateInterval={250.0}
onLoadStart={this.onLoadStart}
onLoad={this.onLoaded}
onProgress={this.onProgressChanged}
onEnd={this.onPlayEnd}
onError={this.onPlayError}
onBuffer={this.onBuffering}
style={{
width: this.state.videoWidth,
height: this.state.videoHeight
}}
/>
{this.state.showVideoCover ? (
<Image
style={{
position: "absolute",
top: 0,
left: 0,
width: this.state.videoWidth,
height: this.state.videoHeight
}}
resizeMode={"cover"}
source={{ uri: this.state.videoCover }}
/>
) : null}
<TouchableWithoutFeedback
onPress={() => {
this.hideControl();
}}
>
<View
style={{
position: "absolute",
top: 0,
left: 0,
width: this.state.videoWidth,
height: this.state.videoHeight,
backgroundColor: this.state.isPlaying
? "transparent"
: "rgba(0, 0, 0, 0.2)",
alignItems: "center",
justifyContent: "center"
}}
>
{this.state.isPlaying ? null : (
<TouchableWithoutFeedback
onPress={() => {
this.onPressPlayButton();
}}
>
<Image style={styles.playButton} source={icon_video_play} />
</TouchableWithoutFeedback>
)}
</View>
</TouchableWithoutFeedback>
{this.state.showVideoControl ? (
<View style={[styles.control, { width: this.state.videoWidth }]}>
<TouchableOpacity
activeOpacity={0.3}
onPress={() => {
this.onControlPlayPress();
}}
>
<Image
style={styles.playControl}
source={this.state.isPlaying ? null : null}
/>
</TouchableOpacity>
<Text style={styles.time}>
{formatTime(this.state.currentTime)}
</Text>
<Slider
style={{ flex: 1 }}
maximumTrackTintColor={"#999999"}
minimumTrackTintColor={"#00c06d"}
// thumbImage={icon_video_play}
value={this.state.currentTime}
minimumValue={0}
maximumValue={this.state.duration}
onValueChange={currentTime => {
this.onSliderValueChanged(currentTime);
}}
/>
<Text style={styles.time}>
{formatTime(this.state.duration)}
</Text>
<TouchableOpacity
activeOpacity={0.3}
onPress={() => {
this.onControlShrinkPress();
}}
>
<Image
style={styles.shrinkControl}
source={this.state.isFullScreen ? null : null}
/>
</TouchableOpacity>
</View>
) : null}
</View>
);
}
定量以及样式
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f0f0f0"
},
playButton: {
width: 50,
height: 50
},
playControl: {
width: 24,
height: 24,
marginLeft: 15
},
shrinkControl: {
width: 15,
height: 15,
marginRight: 15
},
time: {
fontSize: 12,
color: "white",
marginLeft: 10,
marginRight: 10
},
control: {
flexDirection: "row",
height: 44,
alignItems: "center",
backgroundColor: "rgba(0, 0, 0, 0.8)",
position: "absolute",
bottom: 0,
left: 0
}
});
const screenWidth = CommonUtils.width;
function formatTime(second) {
let h = 0,
i = 0,
s = parseInt(second);
if (s > 60) {
i = parseInt(s / 60);
s = parseInt(s % 60);
}
// 补零
let zero = function(v) {
return v >> 0 < 10 ? "0" + v : v;
};
return [zero(h), zero(i), zero(s)].join(":");
}
到这里基本上是大功告成了。
对了还有最重要的一点没说,就是桥接原生,进行页面旋转。具体可以参考我的另一篇文章
react-native 实现单个页面横屏处理https://www.jianshu.com/p/09d0a54c73b2](https://www.jianshu.com/p/09d0a54c73b2