CusVideo.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. import React, { Component } from "react";
  2. import {
  3. Platform,
  4. Text,
  5. View,
  6. ImageBackground,
  7. Button,
  8. Image,
  9. TouchableOpacity,
  10. StyleSheet
  11. } from "react-native";
  12. import { createStackNavigator, createAppContainer } from "react-navigation";
  13. import Video from "react-native-video";
  14. import SeekBar from "../components/SeekBar";
  15. const instructions = Platform.select({
  16. ios: "Press Cmd+R to reload,\n" + "Cmd+D or shake for dev menu",
  17. android:
  18. "Double tap R on your keyboard to reload,\n" +
  19. "Shake or press menu button for dev menu"
  20. });
  21. type Props = {};
  22. export default class CusVideo extends React.Component {
  23. state = {
  24. rate: 1,
  25. volume: 1,
  26. muted: false,
  27. resizeMode: "stretch",
  28. duration: 0.0,
  29. currentTime: 0.0,
  30. paused: false,
  31. wheel: false,
  32. player_status_icon: require("../images/video/start.png"),
  33. isFull: false,
  34. needback: this.props.needback
  35. };
  36. render() {
  37. return (
  38. <View style={this.props.style}>
  39. <Video
  40. style={{ flex: 1 }}
  41. source={{
  42. uri: this.props.uri
  43. }}
  44. ref={ref => {
  45. this.player = ref;
  46. }}
  47. // poster={this.props.poster}
  48. resizeMode={this.state.resizeMode}
  49. // posterResizeMode={this.state.resizeMode}
  50. onBuffer={this.onBuffer}
  51. rate={this.state.rate} //播放速率
  52. paused={this.state.paused} //暂停
  53. volume={this.state.volume} //调节音量
  54. muted={this.state.muted} //控制音频是否静音
  55. resizeMode={this.state.resizeMode} //缩放模式
  56. onLoadStart={this.loadStart} // 当视频开始加载时的回调函数
  57. onLoad={this.onLoad} //加载媒体并准备播放时调用的回调函数。
  58. onProgress={this.onProgress} //视频播放过程中每个间隔进度单位调用的回调函数
  59. onEnd={this.onEnd} //视频播放结束时的回调函数
  60. onAudioBecomingNoisy={this.onAudioBecomingNoisy} //音频变得嘈杂时的回调 - 应暂停视频
  61. onAudioFocusChanged={this.onAudioFocusChanged} //音频焦点丢失时的回调 - 如果焦点丢失则暂停
  62. repeat={this.state.wheel} //确定在到达结尾时是否重复播放视频。
  63. onError={this.onError} // 当视频不能加载,或出错后的回调函数
  64. playInBackground={false} // 当app转到后台运行的时候,播放是否暂停
  65. playWhenInactive={true} // [iOS] Video continues to play when control or notification center are shown. 仅适用于IOS
  66. />
  67. <View
  68. style={{
  69. flexDirection: "row",
  70. position: "absolute",
  71. width: "100%",
  72. height: 50,
  73. alignItems: "center",
  74. justifyContent: "center"
  75. }}
  76. >
  77. <View
  78. style={{
  79. flex: 1,
  80. alignItems: "center"
  81. }}
  82. >
  83. <VideoBack
  84. needback={this.state.needback}
  85. videoback={this.videoBackClick.bind(this)}
  86. />
  87. </View>
  88. <View style={{ flex: 2 }} />
  89. <View
  90. style={{
  91. flex: 9,
  92. overflow: "hidden"
  93. }}
  94. />
  95. <View style={{ flex: 2 }} />
  96. <View
  97. style={{
  98. flex: 1,
  99. alignItems: "center"
  100. }}
  101. />
  102. </View>
  103. <View style={[styles.player_controller]}>
  104. <View
  105. style={{
  106. flex: 1,
  107. alignItems: "center"
  108. }}
  109. >
  110. {/* 暂停播放按钮 */}
  111. <TouchableOpacity
  112. //点击事件放在这个组件里才管用
  113. style={{
  114. justifyContent: "center",
  115. width: "100%",
  116. height: "100%"
  117. }}
  118. onPress={() => this.play()}
  119. >
  120. <Image
  121. style={[styles.player_pause_icon]}
  122. source={this.state.player_status_icon}
  123. />
  124. </TouchableOpacity>
  125. </View>
  126. <View style={{ flex: 2 }}>
  127. {/* //左侧当前播放时长 */}
  128. <Text style={[styles.player_time]}>
  129. {formatTime(this.state.currentTime)}
  130. </Text>
  131. </View>
  132. <View
  133. style={{
  134. flex: 9,
  135. overflow: "hidden"
  136. }}
  137. >
  138. {/* //中间进度条 */}
  139. <SeekBar
  140. style={{ flex: 1 }}
  141. ref={view => (this.seekbar = view)}
  142. //必须带此方法,作为滑动之后抬起的回调
  143. touchUpCallBack={this.touch_up_callback.bind(this)}
  144. />
  145. </View>
  146. <View style={{ flex: 2 }}>
  147. {/* //右侧总时长 */}
  148. <Text style={[styles.player_time]}>
  149. {formatTime(this.state.duration)}
  150. </Text>
  151. </View>
  152. <View
  153. style={{
  154. flex: 1,
  155. alignItems: "center"
  156. }}
  157. >
  158. <TouchableOpacity
  159. style={{
  160. justifyContent: "center",
  161. width: "100%",
  162. height: "100%"
  163. }}
  164. onPress={() => this.presentFullscreenPlayer()}
  165. >
  166. {/* //放大按钮 */}
  167. <Image
  168. style={[styles.fullscreen_icon]}
  169. source={require("../images/video/fullscreen.png")}
  170. />
  171. </TouchableOpacity>
  172. </View>
  173. </View>
  174. </View>
  175. );
  176. }
  177. loadStart() {
  178. // alert("loadStart");
  179. }
  180. onBuffer({ isBuffering }: { isBuffering: boolean }) {
  181. //true为正在加载,false为没有加载,此处给loading提示
  182. console.log("isBuffering:" + isBuffering);
  183. }
  184. onLoad = data => {
  185. //获取的是秒数
  186. this.setState({ duration: data.duration });
  187. this.seekbar.setMax(data.duration);
  188. };
  189. onProgress = data => {
  190. this.setState({
  191. currentTime: data.currentTime
  192. });
  193. this.seekbar.setProgress(this.state.currentTime);
  194. };
  195. onError() {
  196. alert("播放器异常");
  197. }
  198. onEnd() {
  199. alert("播放结束");
  200. }
  201. play() {
  202. if (this.state.paused) {
  203. this.start();
  204. } else {
  205. this.pause();
  206. }
  207. }
  208. pause() {
  209. this.setState({
  210. paused: true,
  211. player_status_icon: require("../images/video/start.png")
  212. });
  213. this.player_icon_index = 1;
  214. }
  215. start() {
  216. this.setState({
  217. paused: false,
  218. player_status_icon: require("../images/video/pause.png")
  219. });
  220. this.player_icon_index = 0;
  221. }
  222. showToast(params) {
  223. // ToastExample.message(params);
  224. ToastExample.show(params, ToastExample.SHORT);
  225. }
  226. seekTo(progress) {
  227. this.player.seek(progress);
  228. }
  229. presentFullscreenPlayer() {
  230. if (this.state.isFull) {
  231. this.setState({
  232. isFull: false,
  233. needback: this.props.needback
  234. });
  235. } else {
  236. this.setState({
  237. isFull: true,
  238. needback: true
  239. });
  240. }
  241. this.props.videofullScreenPlayer();
  242. this.seekbar.setProgress(this.state.currentTime);
  243. }
  244. touch_up_callback(progress) {
  245. //抬起之后,获取算出来的progress
  246. this.setState({
  247. currentTime: progress
  248. });
  249. this.seekTo(progress);
  250. }
  251. refreshVideo() {
  252. this.setState({
  253. duration: 0,
  254. currentTime: 0
  255. });
  256. }
  257. videoBackClick() {
  258. // if (this.props.needback != undefined && this.props.needback) {
  259. // }
  260. if (this.state.isFull) {
  261. //全屏状态下,变小屏
  262. this.presentFullscreenPlayer();
  263. } else {
  264. this.props.videoback();
  265. }
  266. }
  267. }
  268. const styles = StyleSheet.create({
  269. player_controller: {
  270. flexDirection: "row",
  271. position: "absolute",
  272. width: "100%",
  273. height: 50,
  274. alignItems: "center",
  275. justifyContent: "center",
  276. bottom: 0
  277. },
  278. player_pause_icon: {
  279. width: "80%",
  280. resizeMode: "center",
  281. height: "40%",
  282. justifyContent: "center",
  283. alignItems: "center",
  284. left: 5
  285. },
  286. fullscreen_icon: {
  287. width: "80%",
  288. resizeMode: "center",
  289. height: "30%",
  290. justifyContent: "center",
  291. alignItems: "center"
  292. },
  293. player_time: {
  294. fontSize: 18,
  295. color: "white",
  296. alignItems: "center",
  297. justifyContent: "center",
  298. textAlignVertical: "center",
  299. textAlign: "center"
  300. }
  301. });
  302. /**
  303. * 将秒转换为 分:秒
  304. * s int 秒数
  305. */
  306. function formatTime(s) {
  307. //计算分钟
  308. //算法:将秒数除以60,然后下舍入,既得到分钟数
  309. var h;
  310. h = Math.floor(s / 60);
  311. //计算秒
  312. //算法:取得秒%60的余数,既得到秒数
  313. s = Math.round(s % 60);
  314. //将变量转换为字符串
  315. h += "";
  316. s += "";
  317. //如果只有一位数,前面增加一个0
  318. h = h.length == 1 ? "0" + h : h;
  319. s = s.length == 1 ? "0" + s : s;
  320. return h + ":" + s;
  321. }
  322. class VideoBack extends Component {
  323. render() {
  324. if (this.props.needback) {
  325. return (
  326. <TouchableOpacity
  327. //点击事件放在这个组件里才管用
  328. style={{
  329. justifyContent: "center",
  330. width: "100%",
  331. height: "100%"
  332. }}
  333. onPress={() => this.props.videoback()}
  334. >
  335. <Image
  336. style={[styles.player_pause_icon]}
  337. source={require("../images/video/back.png")}
  338. />
  339. </TouchableOpacity>
  340. );
  341. } else {
  342. return null;
  343. }
  344. }
  345. }
  346. /**
  347. 使用方法
  348. <CusVideo
  349. uri={this.state.video_uri}
  350. ref={view => (this.video = view)}
  351. needback={true} //(是否需要小窗口的返回按钮)
  352. videoback={this.clickVideoBack.bind(this)}//(小窗口返回按钮的事件)
  353. videofullScreenPlayer={this.fullScreenPlayer.bind(this)}//(点击全屏按钮的事件)
  354. style={{
  355. flex: this.state.video_flex,
  356. width: this.state.video_width,
  357. height: this.state.video_height
  358. }}
  359. />
  360. */