1.封装组件

src/components/VideoPlayer/index.js

/**
* 视频播放器 组件(VideoPlayer)
*/
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
Dimensions,
ActivityIndicator,
TouchableOpacity,
} from 'react-native';
// 播放器组件
import Video from 'react-native-video';
import Icon from 'react-native-vector-icons/Ionicons'; let {width} = Dimensions.get("window"); export default class VideoPlayer extends Component {
constructor(props) {
super(props);
this.state = {
// 视频播放器
rate: 1, // 是否暂停 0:暂停, 1:正常
muted: false, // 是否静音
resizeMode: 'contain', // 充满整个播放区域 cover 或 自适应 contain
repeat: false, // 是否重复播放 // video control
videoOk: true, // 视频是否出错
videoLoaded: false, // 视频是否加载
playing: false, // 视频是否播放中
paused: false, // 是否暂停
videoProgress: 0.01, // 进度条 // all time
videoTotal: 0, // 视频总时间
currentTime: 0, // 当前时间
}
} render() {
return (
<View style={styles.videoBox}>
<Video
style={styles.video}
ref="videoPlayer"
source={{uri: this.props.uri}}
// 声音放大的倍数: 0 is muted, 1 is double.
volume={5}
// 是否暂停 true or false.
paused={this.state.paused}
// 0 是 暂停, 1 是 正常.
rate={this.state.rate}
// 是否静音 true or false.
muted={this.state.muted}
// 充满整个播放区域 或 自适应
resizeMode={this.state.resizeMode}
// 是否重复播放 true or false.
repeat={this.state.repeat}
// 当视频开始加载时
onLoadStart={this._onLoadStart.bind(this)}
// 当视频在不断的加载时
onLoad={this._onLoad.bind(this)}
// 当视频播放时,每250ms调用一次,便于知悉当前播放位置(时间)
onProgress={this._onProgress.bind(this)}
// 当视频播放结束时调用
onEnd={this._onEnd.bind(this)}
// 当视频出错时调用
onError={this._onError.bind(this)}
/>
{/* 视频出错 */}
{
!this.state.videoOk && <Text style={styles.failText}>视频出错了!很抱歉</Text>
} {/* 没有加载 */}
{
!this.state.videoLoaded && <ActivityIndicator style={styles.loading} color="#ee735c"/>
} {/* 播放结束 */}
{
this.state.videoLoaded && !this.state.playing
?
<Icon
style={styles.playIcon}
onPress={this._rePlay.bind(this)}
name='ios-play'
size={48}
/>
: null
} {/* 视频正在播放,控制是否暂停 */}
{
this.state.videoLoaded && this.state.playing
?
<TouchableOpacity
style={styles.pauseBtn}
onPress={this._pause.bind(this)}
>
{
this.state.paused
?
<Icon
style={styles.resumeIcon}
size={48}
onPress={this._resume.bind(this)}
name="ios-play"
/>
:
<Text></Text>
}
</TouchableOpacity>
: null
}
{/*进度条*/}
<View style={styles.progressBox}>
<View style={[styles.progressBar, {width: width * this.state.videoProgress}]}></View>
</View>
</View>
)
} // 当视频开始加载时
_onLoadStart() {
//
} // 当视频在不断的加载时
_onLoad() {
//
} // 当视频播放时,每250ms调用一次,便于知悉当前播放位置(时间)
_onProgress(data) {
if (!this.state.videoLoaded) {
this.setState({
videoLoaded: true
})
} // 视频中时长
let duration = data.playableDuration;
let currentTime = data.currentTime;
// toFixed(2) get 小数点后两位
let percent = Number((currentTime / duration).toFixed(2));
let newState = {
videoTotal: duration,
currentTime: Number(data.currentTime.toFixed(2)),
videoProgress: percent
}; if (!this.state.videoLoaded) {
newState.videoLoaded = true
}
// 视频暂停播放或播放结束,显示播放按钮
if (!this.state.playing) {
newState.playing = true
} this.setState(newState);
} // 当视频播放结束时调用
_onEnd() {
this.setState({
videoProgress: 1, // 进度为1表示播放结束
playing: false
});
} // 当视频出错时调用
_onError(e) {
this.setState({
videoOk: false
});
} // 重新播放
_rePlay() {
this.refs.videoPlayer.seek(0)
} // 暂停播放
_pause() {
if (!this.state.paused) {
this.setState({
paused: true
})
}
} // 继续播放
_resume() {
if (this.state.paused) {
this.setState({
paused: false
})
}
}
} const styles = StyleSheet.create({
// 视频播放器 容器
videoBox: {
width: width,
height: width * 0.56,
backgroundColor: '#000'
},
// 视频播放器
video: {
width: width,
height: width * 0.56,
backgroundColor: '#000'
},
// 加载动画(菊花图)
loading: {
position: 'absolute',
left: 0,
top: 80,
width: width,
alignSelf: 'center', // 字体居中对齐
backgroundColor: 'transparent'
},
// 视频出错时,文本样式
failText: {
position: 'absolute',
left: 0,
top: 90,
width: width,
textAlign: 'center',
color: '#fff',
backgroundColor: 'transparent'
},
// 进度条样式
progressBox: {
width: width,
height: 2,
backgroundColor: '#ccc'
}, progressBar: {
width: 1,
height: 2,
backgroundColor: '#ff6600'
},
// 播放按钮样式
playIcon: {
position: 'absolute',
top: 90,
left: width / 2 - 30,
width: 60,
height: 60,
paddingTop: 8,
paddingLeft: 22,
backgroundColor: 'transparent',
borderColor: '#fff',
borderWidth: 1,
borderRadius: 30,
color: '#ed7b66'
},
// 暂停
pauseBtn: {
position: 'absolute',
left: 0,
top: 0,
width: width,
height: width * 0.56
},
// 继续
resumeIcon: {
position: 'absolute',
top: 80,
left: width / 2 - 30,
width: 60,
height: 60,
paddingTop: 8,
paddingLeft: 22,
backgroundColor: 'transparent',
borderColor: '#fff',
borderWidth: 1,
borderRadius: 30,
color: '#ed7b66'
}
});

2.调用组件

{/*视频播放器*/}
<VideoPlayer uri={data.video} />

3.效果图

react-native 封装 VedioPlayer 组件的更多相关文章

  1. react native 封装TextInput组件

    上一篇 react-native文章提到了TextInput组件对安卓的适配问题,因此对该组件进行封装很有必要. 文章地址  react native定报预披项目知识点总结 TextInput介绍 官 ...

  2. react native之组织组件

    这些组件包括<TabView>,<NavigatorView>和<ListView>,他们实现了手机端最常用的交互和导航.你会发现这些组件在实际的项目中会非常有用. ...

  3. React Native之倒计时组件的实现(ios android)

    React Native之倒计时组件的实现(ios android) 一,需求分析 1,app需实现类似于淘宝的活动倒计时,并在倒计时结束时,活动也结束. 2,实现订单倒计时,并在倒计时结束时,订单关 ...

  4. React Native封装Toast与加载Loading组件

    React Native开发封装Toast与加载Loading组件 在App开发中,我们避免不了使用的两个组件,一个Toast,一个网络加载Loading,在RN开发中,也是一样,React Nati ...

  5. react native 之子组件和父组件之间的通信

    react native开发中,为了封装性经常需要自定义组件,这样就会出现父组件和子组件,那么怎么在父组件和子组件之间相互通信呢,也就是怎么在各自界面push和pop.传值. 父组件传递给子组件: 父 ...

  6. React Native常用第三方组件汇总--史上最全 之一

    React Native 项目常用第三方组件汇总: react-native-animatable 动画 react-native-carousel 轮播 react-native-countdown ...

  7. React Native常用第三方组件汇总--史上最全[转]

    本文出处: http://blog.csdn.net/chichengjunma/article/details/52920137 React Native 项目常用第三方组件汇总: react-na ...

  8. React Native知识6-NavigatorIOS组件

    NavigatorIOS包装了UIKit的导航功能,可以使用左划功能来返回到上一界面.本组件并非由Facebook官方开发组维护.这一组件的开发完全由社区主导.如果纯js的方案能够满足你的需求的话,那 ...

  9. React Native知识2-Text组件

    Text用于显示文本的React组件,并且它也支持嵌套.样式,以及触摸处理.在下面的例子里,嵌套的标题和正文文字会继承来自styles.baseText的fontFamily字体样式,不过标题上还附加 ...

  10. React Native 系列(五) -- 组件间传值

    前言 本系列是基于React Native版本号0.44.3写的.任何一款 App 都有界面之间数据传递的这个步骤的,那么在RN中,组件间是怎么传值的呢?这篇文章将介绍到顺传.逆传已经通过通知传值. ...

随机推荐

  1. panel(NOIP模拟赛Round 4)

    好吧,,这道题..本来以为挺难的.打了个暴力bfs+hash(期望得分30,实际得分30) 奇特的是,这道题如果不用hash(期望得分20,实际得分100),好吧数据实在是太水了(不会T吗?) 然后我 ...

  2. 华为上机测试题(水仙花数升级版-java)

    PS:这题满分100,没有做对,大家帮忙看看问题在哪 /* * 题目:水仙花数升级版  * 描述: 水仙花数是指一个 n 位数 ( n≥3 ),它的每个位上的数字的 n 次幂之和等于它本身.(例如:1 ...

  3. HTTP GET与POST区别

    HTTP定义了与服务器交互的不同方法,最基本的方法是 GET 和 POST. HTTP-GET和HTTP-POST是使用HTTP的标准协议动词,用于编码和传送变量名/变量值对参数,并且使用相关的请求语 ...

  4. SSM整合过程中出现的问题

    1.Caused by: java.lang.ClassNotFoundException: org.springframework.jdbc.datasource.DataSourceTransac ...

  5. 优化html中mp4视频加载速度

    如果使用参数faststart就会在生成完上边结构之后将moov移动到mdat前面:ffmpeg –i input.flv –c copy –f mp4 –movflags faststart out ...

  6. 第二部分:Spring中配置mongodb

    一.需要引用的jar包 1.spring-data-mongodb-1.9.4.RELEASE.jar 2.spring-data-commons-1.12.11.RELEASE.jar 3.mong ...

  7. hdu 3264(枚举+二分+圆的公共面积)

    Open-air shopping malls Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/ ...

  8. [thinkphp]查看thinkphp系统定义的常量值

    echo 'MEMORY_LIMIT_ON: ' . MEMORY_LIMIT_ON . '<br>'; echo 'THINK_PATH: ' . THINK_PATH . '<b ...

  9. 计蒜客 18487.Divisions-大数的所有因子个数-Miller_Rabin+Pollard_rho-超快的(大数质因解+因子个数求解公式) (German Collegiate Programming Contest 2015 ACM-ICPC Asia Training League 暑假第一阶段第三场 F)

    这一场两个和大数有关的题目,都用到了米勒拉宾算法,有点东西,备忘一下. 题目传送门 F. Divisions 传送门 这个题是求一个数的所有因子个数,但是数据比较大,1e18,所以是大数的题目,正常的 ...

  10. 小白书 黑白图像【DFS/Flood Fill】

    http://blog.csdn.net/u010470972/article/details/33415617 Description 输入一个n×n的黑白图像(1表示黑色,0表示白色),任务是统计 ...