美文网首页
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