ReactNative视频播放器

一、实现参考:(完全参考实现,不喜勿喷)
https://www.cnblogs.com/tengyuxin/p/12030742.html

二、实现播放和组件的依赖

需要三个组件

	1. 播放视频组件, react-native-video    
		官网地址 https://www.npmjs.com/package/react-native-video#allowsexternalplayback

	2. 进度条,官网上提供的 slider组件我忘记说的什么原因,即将停止支持,我找了react-native-silder  
		这个个第三方包 官网地址  https://github.com/react-native-community/react-native-slider#onvaluechange

	3. 全屏播放,react-native-orientation这个包有问题,因为RN 将对 rnpm 换一种支持策略 ,所以选择用 
		react-native-orientation-locker 官网地址  https://github.com/wonday/react-native-orientation-locker

三、实现播放的代码

import React, { PureComponent } from "react";
import PropTypes from "prop-types";
import color from "../../color";
import { View, Text, StyleSheet, TouchableWithoutFeedback, Image, TouchableOpacity, Dimensions } from "react-native";

//导入Video组件
import Video from "react-native-video";

// 导入 Slider组件
import Slider from "@react-native-community/slider";

// 屏幕方向锁定: 他需要改变 原来Android文件代码,当然适配两端的话,IOS也是需要更改的。
import Orientation from "react-native-orientation-locker";

/**
 *  page:{ 视频播放组件 }
 *  function:
 *  time:2021/6/22
 *  author:bai
 */
const windowSize = Dimensions.get("window");//全局属性【用于获取屏幕宽高等信息】
let that;//全局属性【用于保证that的有效区域】
export default class BaseVideo extends PureComponent {

  //提供基本属性和方法
  static propTypes = {
    //视频播放源uri
    videoUri: PropTypes.string,
    //视频默认图片展示,也就是第一帧
    posterImageUri: PropTypes.string,

    //是否支持全屏
    isSupportFullScreen: PropTypes.bool,
  };

  constructor(props) {
    super(props);
    this.playButtonClick = this.playButtonClick.bind(this);
    this.customerSliderValue = this.customerSliderValue.bind(this);
    this.enterFullScreen = this.enterFullScreen.bind(this);
    this._changePauseSliderFullState = this._changePauseSliderFullState.bind(this);
    that = this;

    this.state = {
      isPaused: true,  //是暂停
      duration: 0,      //总时长
      currentTime: 0, //当前播放时间
      sliderValue: 0,   //进度条的进度

      //用来控制进入全屏的属性
      videoViewWidth: windowSize.width,
      videoViewHeight: 226,
      isFullScreen: false,
      isVisiblePausedSliderFullScreen: false,
    };
  }

  /**
   * 初始化屏幕方向
   */
  componentDidMount() {
    let initial = Orientation.getInitialOrientation();
    if (initial === "PORTRAIT") {
      console.log("是竖屏");
    } else {
      console.log("如果是横屏,就将其旋转过来");
      Orientation.lockToPortrait();
    }
  }

  /**
   * Sort排序类型列表
   * @returns {JSX.Element}
   */
  render() {

    // 播放按钮组件:是否显示
    let playButtonComponent = (
      <TouchableWithoutFeedback onPress={this.playButtonClick}>
          <Image style={styles.playBtn} source={require("../../icons/play_icon.png")}/>
      </TouchableWithoutFeedback>
    );

    // 暂停按钮组件:是否显示
    let pauseButtonComponent = (
      <TouchableWithoutFeedback onPress={this.playButtonClick}>
        <Image style={styles.playBtn} source={require("../../icons/pause_icon.png")}/>
      </TouchableWithoutFeedback>
    );

    // 进度条、全屏按钮 是否显示
    let pausedSliderFullComponent = (
      <View style={{ position: "absolute", bottom: 0,height:40,width:windowSize.width,
        paddingLeft:10,paddingRight:10,flexDirection: "row", alignItems: "center" }}>

          {/* 进度条按钮 */}
          <View style={{ flex:5,flexDirection: "row",alignItems: "center",paddingLeft:5,paddingRight:5}}>
            <Text style={{flex:0,color:color.white,fontSize: 12}}>{this.formatMediaTime(that.state.currentTime)}</Text>
            <Slider
              style={{ flex:6, height: 40}}
              value={that.state.sliderValue}
              maximumValue={that.state.duration}
              thumbTintColor="#fff" //开关夹点的颜色
              minimumTrackTintColor="red"
              maximumTrackTintColor="#ccc"
              step={1}
              onValueChange={this.customerSliderValue}/>
            <Text style={{flex:0,color:color.white,fontSize: 12}}>{this.formatMediaTime(that.state.duration)}</Text>
          </View>

          {/* 全屏按钮 */}
          {
            that.props.isSupportFullScreen?<TouchableOpacity style={{flex:0}} onPress={this.enterFullScreen}>
              <Image style={{width:16,height:16,margin:5}} source={that.state.isFullScreen?
                require("../../icons/narrow_screen_icon.png"):require("../../icons/full_screen_icon.png")}/>
            </TouchableOpacity>:null
          }
      </View>
    );

    return (
      <View>
        <TouchableWithoutFeedback onPress={this._changePauseSliderFullState}>

          <Video source={{uri:that.props.videoUri}}
                 ref={(ref) => {that.player = ref;}}
                 style={{ width: that.state.videoViewWidth, height: that.state.videoViewHeight, backgroundColor: "#000000" }}

                 allowsExternalPlayback={false} // 不允许导出 或 其他播放器播放

                 paused={that.state.isPaused} // 控制视频是否播放
                 resizeMode="cover"

                 poster={that.props.posterImageUri}//视频默认图片展示,也就是第一帧
                 posterResizeMode="cover"

                 onLoadStart={(event)=>{
                   //console.log('媒体开始加载时调用的回调函数,开始加载~~~')
                 }}

                 onBuffer={(event)=>{
                   //console.log('远程视频缓冲时调用,正在缓冲~~~')
                 }}

                 onReadyForDisplay={(event)=>{
                   //console.log('当第一个视频帧准备好显示时调用的回调函数。此时海报将被移除;准备好播放展示~~~')
                 }}

                 onEnd={(event)=>{
                   //console.log('播放结束~~~')
                   //播放结束后,展示播放按钮,点击重新播放
                   that.setState({
                     isPaused:true,
                     sliderValue:0
                   },()=>{
                     //播放完成,设置默认图片展示(第一帧)
                     that.player.setState({
                       showPoster: true
                     })
                     //重新播放【必须要设置isPaused:true之后】
                     //that.playButtonClick()
                   })
                 }}

                 onLoad={(e) => this.customerOnload(e)}

                 onProgress={(e) => this.customerOnprogress(e)}

                 fullscreen={that.state.isFullScreen}
          />
        </TouchableWithoutFeedback>

        {/* 播放的按钮:点击之后需要消失 */}
        {that.state.isPaused?playButtonComponent:null}

        {/* 暂停按钮 */}
        {(that.state.isVisiblePausedSliderFullScreen &&!that.state.isPaused)? pauseButtonComponent : null}

        {/* 进度条,全屏按钮 */}
        {that.state.isVisiblePausedSliderFullScreen ? pausedSliderFullComponent : null}

      </View>
    );
  }

  /**
   * 控制按钮显示播放,要显示进度条N秒钟,之后关闭显示
   */
  playButtonClick() {

    //设置播放视频、展示进度条和全屏按钮
    that.setState({
      isPaused: !that.state.isPaused,
      isVisiblePausedSliderFullScreen: true,
    });

    //设置默认图片不展示(第一帧)
    that.player.setState({
      showPoster: false
    })

    //定时,处理进度条和全屏按钮、暂停按钮,多长时间后关闭显示
    setTimeout(function() {
      that.setState({
        isVisiblePausedSliderFullScreen: false,
      });
    }, 10000);
  }

  /**
   * 单击事件,是否显示 “暂停、进度条、全屏按钮 盒子”
   * @private
   */
  _changePauseSliderFullState() {
    let flag = !that.state.isVisiblePausedSliderFullScreen;
    that.setState({
      isVisiblePausedSliderFullScreen: flag,
    });
    setTimeout(function() {
      that.setState({
        isVisiblePausedSliderFullScreen: false,
      });
    }, 10000);
  }

  /**
   * 格式化音乐播放的时间为0:00。借助onProgress的定时器调用,更新当前时间
   * @param time
   * @returns {string}
   */
  formatMediaTime(time) {
    let minute = Math.floor(time / 60);
    let second = parseInt(time - minute * 60);
    minute = minute >= 10 ? minute : "0" + minute;
    second = second >= 10 ? second : "0" + second;
    return minute + ":" + second;
  }

  /**
   * 加载视频调用,主要是拿到 “总时间”,并格式化
   * @param e
   */
  customerOnload(e) {
    let time = e.duration;
    that.setState({
      duration: time,
    });
  }

  /**
   * 获得当前的,播放时间数,但这个数是0.104,需要处理
   * @param e
   */
  customerOnprogress(e) {
    let time = e.currentTime;   // 获取播放视频的秒数
    that.setState({
      currentTime: time,
      sliderValue: time,
    });
  }

  /**
   * 移动滑块,改变视频播放进度
   * @param value
   */
  customerSliderValue(value) {
    that.player.seek(value);
  }

  /**
   * 全屏
   * 1.改变宽高
   * 2.允许进入全屏模式
   * 3.如何配置屏幕旋转,不需要改变进度条盒子的显示和隐藏
   */
  enterFullScreen() {
    if(that.state.isFullScreen){
      that.setState({
        videoViewWidth: windowSize.width,
        videoViewHeight: 226,
        isFullScreen: false,
      });
      // 直接设置方向
      Orientation.lockToPortrait();
    }else{
      that.setState({
        videoViewWidth: windowSize.height,
        videoViewHeight: windowSize.width,
        isFullScreen: true,
      });
      // 直接设置方向
      Orientation.lockToLandscape();
    }
  }

}

//全局样式
const styles = StyleSheet.create({
  myVideo: {
    width: 340,
    height: 240,
  },
  playBtn: {
    width: 30,
    height: 30,
    position: "absolute",
    top: "50%",
    left: "50%",
    marginLeft: -15,
    marginTop: -15,
    zIndex: 999,
  },
});


四、demo引用的icons
在这里插入图片描述
五、引用组件

import BaseVideo from "../../widget/Common/VideoViews/BaseVideo";
<BaseVideo videoUri={"https://v-cdn.zjol.com.cn/276984.mp4"}
		   posterImageUri={"https://baconmockup.com/300/200/"}/>
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值