react-native 封装 VedioPlayer 组件

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 * 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,
    height: width * 0.56,
    backgroundColor: '#000'
  },
  // 视频播放器
  video: {
     width,
    height: width * 0.56,
    backgroundColor: '#000'
  },
  // 加载动画(菊花图)
  loading: {
    position: 'absolute',
    left: 0,
    top: 80,
     width,
    alignSelf: 'center', // 字体居中对齐
    backgroundColor: 'transparent'
  },
  // 视频出错时,文本样式
  failText: {
    position: 'absolute',
    left: 0,
    top: 90,
     width,
    textAlign: 'center',
    color: '#fff',
    backgroundColor: 'transparent'
  },
  // 进度条样式
  progressBox: {
     width,
    height: 2,
    backgroundColor: '#ccc'
  },

  progressBar: {
     1,
    height: 2,
    backgroundColor: '#ff6600'
  },
  // 播放按钮样式
  playIcon: {
    position: 'absolute',
    top: 90,
    left: width / 2 - 30,
     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,
    height: width * 0.56
  },
  // 继续
  resumeIcon: {
    position: 'absolute',
    top: 80,
    left: width / 2 - 30,
     60,
    height: 60,
    paddingTop: 8,
    paddingLeft: 22,
    backgroundColor: 'transparent',
    borderColor: '#fff',
    borderWidth: 1,
    borderRadius: 30,
    color: '#ed7b66'
  }
});

2.调用组件

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

3.效果图

原文地址:https://www.cnblogs.com/crazycode2/p/9427898.html