美文网首页
RN video和orientation的联合使用

RN video和orientation的联合使用

作者: 安卓小白之小楼又东风 | 来源:发表于2018-08-23 12:21 被阅读178次

首先是准备工作,安装着两个库:
1、安装video、orientation库,以及配置。

yarn add react-native-video

然后link

react-native link

详情见:https://github.com/react-native-community/react-native-video#installation
安装orientation库,

yarn add react-native-orientation
react-native link

详情请看:https://github.com/yamill/react-native-orientation
2、学习一些基本的属性和方法。
(1)orientation(你需要了解RN的生命周期)
添加监听和移除监听:
添加监听:
需要在生命周期方中进行

  componentDidMount() {
    Orientation.addOrientationListener((orientation)=>{});
    Orientation.addSpecificOrientationListener((specificOrientation)=>{});
  }

orientation 将返回以下值之一:

LANDSCAPE
PORTRAIT
PORTRAITUPSIDEDOWN
UNKNOWN

specificOrientation 将返回以下值之一:

LANDSCAPE-LEFT
LANDSCAPE-RIGHT
PORTRAIT
PORTRAITUPSIDEDOWN
UNKNOWN
移除监听:

componentWillUnmount() {
    Orientation.removeOrientationListener(this._updateOrientation);
    Orientation.removeSpecificOrientationListener(this._updateSpecificOrientation);
  }

2、初始化:

  componentWillMount() {
    const init = Orientation.getInitialOrientation();//得到最初的手机屏幕
    this.setState({
      init,
      orientation: init,
      specificOrientation: init,
    });
  }

3、API
lockToPortrait():竖屏锁定
lockToLandscape():横屏锁定,但不锁定左右横屏
lockToLandscapeLeft():左横屏
lockToLandscapeRight():右横屏
unlockAllOrientations():解除所有锁定
getOrientation((err, orientation) => {}):得到当前屏幕的信息
getSpecificOrientation((err, specificOrientation) => {}):同上
4、实例demo:

import React, { Component } from 'react';
import { Alert, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import Orientation from 'react-native-orientation';

export default class Demo extends Component {
  componentWillMount() {
    const init = Orientation.getInitialOrientation();
    this.setState({
      init,
      orientation: init,
      specificOrientation: init,
    });
  }

  componentDidMount() {
    Orientation.addOrientationListener(this._updateOrientation);
    Orientation.addSpecificOrientationListener(this._updateSpecificOrientation);
  }

  componentWillUnmount() {
    Orientation.removeOrientationListener(this._updateOrientation);
    Orientation.removeSpecificOrientationListener(this._updateSpecificOrientation);
  }

  _getOrientation() {
    Orientation.getOrientation((err, orientation) => {
      Alert.alert(`Orientation is ${orientation}`);
    });
  }

  _getSpecificOrientation() {
    Orientation.getSpecificOrientation((err, orientation) => {
      Alert.alert(`Specific orientation is ${orientation}`);
    });
  }

  _updateOrientation = (orientation) => this.setState({ orientation });
  _updateSpecificOrientation = (specificOrientation) => this.setState({ specificOrientation });

  render() {
    const { init, orientation, specificOrientation } = this.state;

    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native Orientation Demo!
        </Text>
        <Text style={styles.instructions}>
          {`Initial Orientation: ${init}`}
        </Text>
        <Text style={styles.instructions}>
          {`Current Orientation: ${orientation}`}
        </Text>
        <Text style={styles.instructions}>
          {`Specific Orientation: ${specificOrientation}`}
        </Text>
        <TouchableOpacity
          onPress={Orientation.unlockAllOrientations}
          style={styles.button}
        >
          <Text style={styles.instructions}>
            Unlock All Orientations
          </Text>
        </TouchableOpacity>
        <TouchableOpacity
          onPress={Orientation.lockToPortrait}
          style={styles.button}
        >
          <Text style={styles.instructions}>
            Lock To Portrait
          </Text>
        </TouchableOpacity>
        <View style={styles.buttonContainer}>
          <TouchableOpacity
            onPress={Orientation.lockToLandscapeLeft}
            style={styles.button}
          >
            <Text style={styles.instructions}>
              Lock To Left
            </Text>
          </TouchableOpacity>
          <TouchableOpacity
            onPress={Orientation.lockToLandscape}
            style={styles.button}
          >
            <Text style={styles.instructions}>
              Lock To Landscape
            </Text>
          </TouchableOpacity>
          <TouchableOpacity
            onPress={Orientation.lockToLandscapeRight}
            style={styles.button}
          >
            <Text style={styles.instructions}>
              Lock To Right
            </Text>
          </TouchableOpacity>
        </View>
        <View style={styles.buttonContainer}>
          <TouchableOpacity
            onPress={this._getOrientation}
            style={styles.button}
          >
            <Text style={styles.instructions}>
              Get Orientation
            </Text>
          </TouchableOpacity>
          <TouchableOpacity
            onPress={this._getSpecificOrientation}
            style={styles.button}
          >
            <Text style={styles.instructions}>
              Get Specific Orientation
            </Text>
          </TouchableOpacity>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
  buttonContainer: {
    flex: 0,
    flexDirection: 'row',
    justifyContent: 'space-around'
  },
  button: {
    padding: 5,
    margin: 5,
    borderWidth: 1,
    borderColor: 'white',
    borderRadius: 3,
    backgroundColor: 'grey',
  }
});

(这是orientation的实例Demo)见:https://github.com/yamill/react-native-orientation/blob/master/demo/app.js
实例图:

orientationOne.png
(2)Video
一大堆属性:
真的是很多我就不一一举出:详情见:https://www.npmjs.com/package/react-native-video

source:这个跟图片资源是一样的。
audioOnly:仅播放音频(boolean)
paused:是否暂停(boolean)
playInBackground:是否允许后台播放(boolean)
rate:视频倍速(num)
0.0 - 暂停视频
1.0 - 以正常速度播放
其他值 - 减慢或加快播放速度
volume:声音
1.0(默认) - 以全音量播放
0.0 - 静音
其他值 - 减少音量
repeat:是否循环播放(boolean)
muted:是否静音
resizeMode
确定当帧与原始视频尺寸不匹配时如何调整视频大小。

“无”(默认) - 不应用调整大小
“包含” - 统一缩放视频(保持视频的宽高比),使视频的尺寸(宽度和高度)等于或小于视图的相应尺寸(减去填充)。
“cover” - 均匀缩放视频(保持视频的宽高比),使图像的尺寸(宽度和高度)等于或大于视图的相应尺寸(减去填充)。
“stretch” - 独立缩放宽度和高度,这可能会改变src的宽高比。
平台:Android ExoPlayer,Android MediaPlayer,iOS,Windows UWP
方法:

onLoad

Callback function that is called when the media is loaded and ready to play.

Payload:

Property Type Description
currentPosition number Time in seconds where the media will start
duration number Length of the media in seconds
naturalSize object Properties:
  • width - Width in pixels that the video was encoded at
  • height - Height in pixels that the video was encoded at
  • orientation - "portrait" or "landscape" |
    | audioTracks | array | An array of audio track info objects with the following properties:
  • index - Index number
  • title - Description of the track
  • language - 2 letter ISO 639-1 or 3 letter ISO639-2 language code
  • type - Mime type of track |
    | textTracks | array | An array of text track info objects with the following properties:
  • index - Index number
  • title - Description of the track
  • language - 2 letter ISO 639-1 or 3 letter ISO 639-2 language code
  • type - Mime type of track |

onProgress
Callback function that is called every progressInterval seconds with info about which position the media is currently playing.

Property Description
currentTime number
playableDuration number
seekableDuration number

seek()
seek(seconds)

Seek to the specified position represented by seconds. seconds is a float value.

seek() can only be called after the onLoad event has fired.

'use strict';

import React, {
  Component
} from 'react';

import {
  AppRegistry,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';

import Video from 'react-native-video';

class VideoPlayer extends Component {

  state = {
    rate: 1,
    volume: 1,
    muted: false,
    resizeMode: 'contain',
    duration: 0.0,
    currentTime: 0.0,
    paused: true,
  };

  video: Video;

  onLoad = (data) => {
    this.setState({ duration: data.duration });
  };

  onProgress = (data) => {
    this.setState({ currentTime: data.currentTime });
  };

  onEnd = () => {
    this.setState({ paused: true })
    this.video.seek(0)
  };

  onAudioBecomingNoisy = () => {
    this.setState({ paused: true })
  };

  onAudioFocusChanged = (event: { hasAudioFocus: boolean }) => {
    this.setState({ paused: !event.hasAudioFocus })
  };

  getCurrentTimePercentage() {
    if (this.state.currentTime > 0) {
      return parseFloat(this.state.currentTime) / parseFloat(this.state.duration);
    }
    return 0;
  };

  renderRateControl(rate) {
    const isSelected = (this.state.rate === rate);

    return (
      <TouchableOpacity onPress={() => { this.setState({ rate }) }}>
        <Text style={[styles.controlOption, { fontWeight: isSelected ? 'bold' : 'normal' }]}>
          {rate}x
        </Text>
      </TouchableOpacity>
    );
  }

  renderResizeModeControl(resizeMode) {
    const isSelected = (this.state.resizeMode === resizeMode);

    return (
      <TouchableOpacity onPress={() => { this.setState({ resizeMode }) }}>
        <Text style={[styles.controlOption, { fontWeight: isSelected ? 'bold' : 'normal' }]}>
          {resizeMode}
        </Text>
      </TouchableOpacity>
    )
  }

  renderVolumeControl(volume) {
    const isSelected = (this.state.volume === volume);

    return (
      <TouchableOpacity onPress={() => { this.setState({ volume }) }}>
        <Text style={[styles.controlOption, { fontWeight: isSelected ? 'bold' : 'normal' }]}>
          {volume * 100}%
        </Text>
      </TouchableOpacity>
    )
  }

  render() {
    const flexCompleted = this.getCurrentTimePercentage() * 100;
    const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;

    return (
      <View style={styles.container}>
        <TouchableOpacity
          style={styles.fullScreen}
          onPress={() => this.setState({ paused: !this.state.paused })}
        >
          <Video
            ref={(ref: Video) => { this.video = ref }}
            /* For ExoPlayer */
            /* source={{ uri: 'http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0', type: 'mpd' }} */
            source={require('./broadchurch.mp4')}
            style={styles.fullScreen}
            rate={this.state.rate}
            paused={this.state.paused}
            volume={this.state.volume}
            muted={this.state.muted}
            resizeMode={this.state.resizeMode}
            onLoad={this.onLoad}
            onProgress={this.onProgress}
            onEnd={this.onEnd}
            onAudioBecomingNoisy={this.onAudioBecomingNoisy}
            onAudioFocusChanged={this.onAudioFocusChanged}
            repeat={false}
          />
        </TouchableOpacity>

        <View style={styles.controls}>
          <View style={styles.generalControls}>
            <View style={styles.rateControl}>
              {this.renderRateControl(0.25)}
              {this.renderRateControl(0.5)}
              {this.renderRateControl(1.0)}
              {this.renderRateControl(1.5)}
              {this.renderRateControl(2.0)}
            </View>

            <View style={styles.volumeControl}>
              {this.renderVolumeControl(0.5)}
              {this.renderVolumeControl(1)}
              {this.renderVolumeControl(1.5)}
            </View>

            <View style={styles.resizeModeControl}>
              {this.renderResizeModeControl('cover')}
              {this.renderResizeModeControl('contain')}
              {this.renderResizeModeControl('stretch')}
            </View>
          </View>

          <View style={styles.trackingControls}>
            <View style={styles.progress}>
              <View style={[styles.innerProgressCompleted, { flex: flexCompleted }]} />
              <View style={[styles.innerProgressRemaining, { flex: flexRemaining }]} />
            </View>
          </View>
        </View>
      </View>
    );
  }
}


const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'black',
  },
  fullScreen: {
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
  },
  controls: {
    backgroundColor: 'transparent',
    borderRadius: 5,
    position: 'absolute',
    bottom: 20,
    left: 20,
    right: 20,
  },
  progress: {
    flex: 1,
    flexDirection: 'row',
    borderRadius: 3,
    overflow: 'hidden',
  },
  innerProgressCompleted: {
    height: 20,
    backgroundColor: '#cccccc',
  },
  innerProgressRemaining: {
    height: 20,
    backgroundColor: '#2C2C2C',
  },
  generalControls: {
    flex: 1,
    flexDirection: 'row',
    borderRadius: 4,
    overflow: 'hidden',
    paddingBottom: 10,
  },
  rateControl: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
  },
  volumeControl: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
  },
  resizeModeControl: {
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  controlOption: {
    alignSelf: 'center',
    fontSize: 11,
    color: 'white',
    paddingLeft: 2,
    paddingRight: 2,
    lineHeight: 12,
  },
});

Video 的demo:https://github.com/react-native-community/react-native-video/blob/master/example/index.android.js

下面是我结合使用的情况:

import React, {
    Component
} from 'react';

import {
    AppRegistry,
    StyleSheet,
    Text,
    TouchableOpacity,
    View,
    Image,
    Dimensions
} from 'react-native';
let {width,height} = Dimensions.get('window');
import Video from 'react-native-video';
import Orientation from 'react-native-orientation';
export default class VideoTest extends Component {

    state = {
        rate: 1,
        volume: 1,
        muted: false,
        resizeMode: 'contain',
        duration: 0.0,
        currentTime: 0.0,
        paused: true,
    };

    componentWillMount(){
        const init = Orientation.getInitialOrientation();
        this.setState({
            orientation:init,
        })
    };

    componentDidMount(){
        Orientation.addOrientationListener(this.updateOrientation)
    }

    componentWillUnmount(){
        Orientation.removeOrientationListener(this.updateOrientation);
    }

    updateOrientation = (orientation) => this.setState({orientation});

    Change(){
        if(this.state.orientation === 'PORTRAIT'){
            Orientation.lockToLandscape();
            this.setState({
                orientation:'LANDSCAPE'
            })
        }else{
            Orientation.lockToPortrait();
            this.setState({
                orientation:'PORTRAIT'
            })
        }
    }

    //video: Video;

    onLoad = (data) => {
        this.setState({ duration: data.duration });
    };

    onProgress = (data) => {
        this.setState({ currentTime: data.currentTime });
    };

    onEnd = () => {
        this.setState({ paused: true });
        this.video.seek(0);
    };

    onAudioBecomingNoisy = () => {
        this.setState({ paused: true })
    };

    onAudioFocusChanged = (event: { hasAudioFocus: boolean }) => {
        this.setState({ paused: !event.hasAudioFocus })
    };

    getCurrentTimePercentage() {
        if (this.state.currentTime > 0) {
            return parseFloat(this.state.currentTime) / parseFloat(this.state.duration);
        }
        return 0;
    };

    renderRateControl(rate) {
        const isSelected = (this.state.rate === rate);

        return (
            <TouchableOpacity onPress={() => { this.setState({ rate }) }}>
                <Text style={[styles.controlOption, { fontWeight: isSelected ? 'bold' : 'normal' }]}>
                    {rate}x
                </Text>
            </TouchableOpacity>
        );
    }

    renderResizeModeControl(resizeMode) {
        const isSelected = (this.state.resizeMode === resizeMode);

        return (
            <TouchableOpacity onPress={() => { this.setState({ resizeMode }) }}>
                <Text style={[styles.controlOption, { fontWeight: isSelected ? 'bold' : 'normal' }]}>
                    {resizeMode}
                </Text>
            </TouchableOpacity>
        )
    }

    renderVolumeControl(volume) {
        const isSelected = (this.state.volume === volume);

        return (
            <TouchableOpacity onPress={() => { this.setState({ volume }) }}>
                <Text style={[styles.controlOption, { fontWeight: isSelected ? 'bold' : 'normal' }]}>
                    {volume * 100}%
                </Text>
            </TouchableOpacity>
        )
    }

    render() {
        const flexCompleted = this.getCurrentTimePercentage() * 100;
        const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;
        return (
            <View style={styles.container}>
                <TouchableOpacity
                    style={styles.fullScreen}
                    onPress={() => this.setState({ paused: !this.state.paused })}
                >
                    <Video
                        ref={(ref: Video) => { this.video = ref }}
                        /* For ExoPlayer */
                        /* source={{ uri: 'http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0', type: 'mpd' }} */
                        //source={require('./img/video.mp4')}
                        source={{uri:'http://baobab.kaiyanapp.com/api/v1/playUrl?vid=121398&resourceType=video&editionType=normal&source=aliyun'}}
                        //audioOnly={true}
                        playInBackground={true}
                        //poster='https://baconmockup.com/300/200/'
                        style={styles.fullScreen}
                        rate={this.state.rate}
                        paused={this.state.paused}
                        volume={this.state.volume}
                        muted={this.state.muted}
                        resizeMode={this.state.resizeMode}
                        onLoad={this.onLoad}
                        onProgress={this.onProgress}
                        onEnd={this.onEnd}
                        onAudioBecomingNoisy={this.onAudioBecomingNoisy}
                        onAudioFocusChanged={this.onAudioFocusChanged}
                        repeat={false}
                    />
                </TouchableOpacity>
                {this.state.paused ? <Image source={{uri:'http://ww1.sinaimg.cn/large/005T39qagy1fuiz5uzl1zj301e01e0dx.jpg'}}
                                            style={{width:30,height:30}}
                />:null}
                <View style={styles.controls}>
                    <View style={styles.generalControls}>
                        <View style={styles.rateControl}>
                            {this.renderRateControl(0.25)}
                            {this.renderRateControl(0.5)}
                            {this.renderRateControl(1.0)}
                            {this.renderRateControl(1.5)}
                            {this.renderRateControl(2.0)}
                        </View>

                        <View style={styles.volumeControl}>
                            {this.renderVolumeControl(0.5)}
                            {this.renderVolumeControl(1)}
                            {this.renderVolumeControl(1.5)}
                        </View>

                        <View style={styles.resizeModeControl}>
                            {this.renderResizeModeControl('cover')}
                            {this.renderResizeModeControl('contain')}
                            {this.renderResizeModeControl('stretch')}
                        </View>
                    </View>

                    <View style={styles.trackingControls}>
                        <View style={styles.progress}>
                            <View style={[styles.innerProgressCompleted, { flex: flexCompleted }]} />
                            <View style={[styles.innerProgressRemaining, { flex: flexRemaining }]} />
                        </View>
                    </View>
                    <View style={{flexDirection:'row',justifyContent:'space-between'}}>
                    <TouchableOpacity
                        onPress={()=>{
                            if(this.state.muted){
                                this.setState({muted:false})
                            }else{
                                this.setState({muted:true})
                            }
                        }}
                    >
                        <Image source={{uri:'http://ww1.sinaimg.cn/large/005T39qagy1fu5pr4xhesj300q00q0ir.jpg'}}
                               style={{width:20,height:20}}
                        />
                    </TouchableOpacity>
                    <TouchableOpacity
                        onPress={this.Change.bind(this)}
                    >
                        <Image source={{uri:'http://ww1.sinaimg.cn/large/005T39qagy1fuiyd51g0gj300o00o06h.jpg'}}
                               style={{width:20,height:20}}
                        />
                    </TouchableOpacity>
                    </View>
                </View>
            </View>
        );
    }
}


const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: 'black',
    },
    fullScreen: {
        position: 'absolute',
        top: 0,
        left: 0,
        bottom: 0,
        right: 0,
    },
    controls: {
        backgroundColor: 'transparent',
        borderRadius: 5,
        position: 'absolute',
        bottom: 20,
        left: 20,
        right: 20,
    },
    progress: {
        flex: 1,
        flexDirection: 'row',
        borderRadius: 3,
        overflow: 'hidden',
    },
    innerProgressCompleted: {
        height: 20,
        backgroundColor: '#cccccc',
    },
    innerProgressRemaining: {
        height: 20,
        backgroundColor: '#2C2C2C',
    },
    generalControls: {
        flex: 1,
        flexDirection: 'row',
        borderRadius: 4,
        overflow: 'hidden',
        paddingBottom: 10,
    },
    rateControl: {
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'center',
    },
    volumeControl: {
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'center',
    },
    resizeModeControl: {
        flex: 1,
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'center',
    },
    controlOption: {
        alignSelf: 'center',
        fontSize: 11,
        color: 'white',
        paddingLeft: 2,
        paddingRight: 2,
        lineHeight: 12,
    },
});

效果图:

![ Two.png
Screenshot_2018-08-23-12-19-35.png

相关文章

网友评论

      本文标题:RN video和orientation的联合使用

      本文链接:https://www.haomeiwen.com/subject/ybrpiftx.html