问题:为什么 react native video 不能全屏播放视频?

IT技术 android reactjs react-native
2021-04-28 14:40:23

我为Android创建应用程序和IOSreact天然的(0.57.7),并使用react本地视频播放上传到视频VIMEO集成react视频插件后,在两个设备上测试。ios 中它运行良好,但在 android 中,我无法以全屏模式播放视频。这是我的Android代码:

import React, { PureComponent } from 'react';
import {
    View,
    Text,
    Image,
    ImageBackground,
    StyleSheet,
    SafeAreaView,
    TouchableOpacity,
    ActivityIndicator
} from 'react-native';

import PropTypes from 'prop-types'

import Video from "react-native-video";
import Orientation from 'react-native-orientation-locker';
import { widthPercentageToDP as wp, heightPercentageToDP as hp } from '../components/Resposive';
import RF from "react-native-responsive-fontsize"

export default class Videoplayer extends PureComponent {


    constructor(props){
        super(props);
        this.state = {
            loading: true,
            videoFileArr:[],
            showPlayer:false,
            playing:false
        }
    }

    componentDidMount() {
        Orientation.lockToLandscape();
        this.fetchVimeoVideo();
    }

    componentWillUnmount() {
        Orientation.lockToPortrait();
    }

    goToHome(){
        Orientation.lockToPortrait();
        this.props.navigation.goBack();
    }

    fetchVimeoVideo = async () => {
        await this.setState({ loading: true });

        const { navigation } = this.props;
        const jsonReceived = navigation.getParam('item', {})
        const url = "https://api.vimeo.com/me/videos/" + jsonReceived.video_link
        console.log(url)
        const response = await fetch(
            url, {
                method: "get",
                headers: {
                    Accept: 'application/json',
                    'Content-Type': 'application/json',
                    Authorization:"Bearer f9e937d64037e657addcf088f28e6cb5"
                }
            });
        const jsonResponse = await response.json();

        const { files} = jsonResponse;
        if (response.status != 200) {
            alert(response.status)
        }

        console.log(files)
        await this.setState({ videoFileArr:files, loading: false });
    };



    renderOptions = () => {
        if (this.state.loading === true) {
            return (
                <View style={{
                    flex: 1,
                    alignItems: "center",
                    justifyContent: "center"
                }}>
                    <ActivityIndicator size="large" color="#00ff00" />
                    <Text style={{ fontFamily: "Futura Std", fontSize: RF(3.0), fontWeight: "900", color: "#244E25", textAlign: "center" }}>Please wait while we are loading questions for you</Text>
                </View>
            )
        }else if (this.state.videoFileArr.length> 0 && this.state.playing === false) {

            const { navigation } = this.props;
            const jsonReceived = navigation.getParam('item', {})
            return(
                <ImageBackground style={{width:"100%",height:"100%",alignItems:"center",justifyContent:"center"}}  source={{uri:jsonReceived.video_banner}}> 
                    <TouchableOpacity
                        onPress={() => {
                            this.setState({playing:true})
                        }}
                    >
                        <Image source={require("../assets/Common/Play/playIcon.png")}/>
                    </TouchableOpacity>
                </ImageBackground>
            )

        } else if (this.state.videoFileArr.length > 0 && this.state.playing === true) {
            return (
                <View style={styles.container}>
                    <Video source={{ uri:this.state.videoFileArr[0].link}}   // Can be a URL or a local file.
                        ref={ ref => 
                            this.player = ref
                        }                                      // Store reference
                        onBuffer={this.onBuffer}                // Callback when remote video is buffering
                        onError={this.videoError}               // Callback when video cannot be loaded
                        style={styles.backgroundVideo}
                        controls={true}
                        paused={false}
                        fullscreen={true}
                    />
                </View>
            )
        }
    }

    render() {
        return (
            <SafeAreaView style={{ flex: 1 }}>
                <View style={{ flex: 1, overflow: "hidden" }}>


                    <View style={{ flex: 1, backgroundColor: "green" }}>
                        {this.renderOptions()}
                    </View>

                    {/* top navigationBar */}
                    <View
                        style={{
                            position: "absolute",
                            top: 0,
                            left: 0,
                            right: 0,
                            width: "100%",
                            flexDirection: "row",
                            justifyContent: "space-between",
                            alignItems: "center",
                            height: 80,
                            backgroundColor: null
                        }}
                    >
                        <TouchableOpacity onPress={
                            ()=>this.goToHome()
                        }>
                            <Image style={{ margin: 8 }} source={require("../assets/Common/goBack/goBack.png")} />
                        </TouchableOpacity>

                        <TouchableOpacity>
                            <Image style={{ margin: 8 }} source={require("../assets/Common/Star/starOff.png")} />
                        </TouchableOpacity>

                    </View>
                </View>
            </SafeAreaView>
        )
    }
}

const styles = StyleSheet.create({
    container:{ flex: 1, justifyContent: "center"},
    backgroundVideo: {
      position: 'absolute',
      top: 0,
      left: 0,
      bottom: 0,
      right: 0,
    },
});

这是我无法全屏播放视频的输出屏幕:

在此处输入图片说明

请帮忙,我做错了什么?

4个回答

我已经解决了视频帧的全屏问题,只是在 Video 组件上添加了 resizeMode:

<Video source={{ uri:this.state.videoFileArr[0].link}}   // Can be a URL or a local file.
    ref={ ref => 
        this.player = ref
    }                                      // Store reference
    onBuffer={this.onBuffer}                // Callback when remote video is buffering
    onError={this.videoError}               // Callback when video cannot be loaded
    style={styles.backgroundVideo}
    controls={true}
    paused={false}
    fullscreen={true}
    resizeMode="cover"
/>

几天前我一直在为同样的问题苦苦挣扎,但我让它在 android 中为我工作。我希望这也能帮助你。

您还需要安装其他一些软件包,即 1. react-native-video-controls 2. react-native-orientation

现在在将播放视频的屏幕中。

import React, { Component } from 'react'
import {
Text,
StyleSheet,
StatusBar,
Dimensions,
Alert,
Modal,
BackHandler,
TouchableOpacity,
ToastAndroid,
} from 'react-native'

import { Container, View, Button, Icon, List, ListItem } from 'native-base';
import Video from 'react-native-video';
import Orientation from 'react-native-orientation';
const sample = require('../assets/demo.mp4');

export default class Player extends Component {
constructor(props) {
    super(props);
    this.onLoad = this.onLoad.bind(this);
    this.onProgress = this.onProgress.bind(this);
}


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

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

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

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

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

    return (
        <ListItem>
            <TouchableOpacity onPress={() => { this.setState({ rate: rate }) }}>
                <Text style={{ fontWeight: isSelected ? "bold" : "normal" }}>
                    {rate}x
</Text>
            </TouchableOpacity>
        </ListItem>
    )
}

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

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

fullScreen = () => {
    Orientation.getOrientation((err, orientation) => {
        if (orientation == 'LANDSCAPE') {
            Orientation.lockToPortrait();
        } else {
            Orientation.lockToLandscape();
        }
    });

}

backAction = () => {
    Orientation.getOrientation((err, orientation) => {
        if (orientation == 'LANDSCAPE') {
            Orientation.lockToPortrait();
        }
    });
};

componentDidMount() {
    this.backHandler = BackHandler.addEventListener(
        "hardwareBackPress",
        this.backAction
    );
}

componentWillUnmount() {
    this.backHandler.remove();
}
render() {
    const { modalVisible, paused } = this.state
    const url = `https://www.sample- 
 videos.com/video/mp4/720/big_buck_bunny_720p_10mb.mp4`;
    const flexCompleted = this.getCurrentTimePercentage() * 100;
    const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;
    return (
        <View style={styles.container}>
            <StatusBar hidden={true} />

            <Video source={sample}
                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={() => { alert('Done!') }}
                controls
                repeat={true} />
            <View style={[{ left: 0 }, styles.rateControl]}>
                <Button
                    transparent
                    onPress={() => {
                        this.fullScreen();
                    }}
                >
                    <Icon type="FontAwesome5" name="compress" style={{ color: "#fff", 
fontSize: 15 }} />
                </Button>
            </View>
            <View style={styles.rateControl}>
                <Button
                    transparent
                    onPress={() => {
                        this.setModalVisible(true);
                    }}
                >
                    <Icon type="FontAwesome5" name="ellipsis-v" style={{ color: 
"#fff", fontSize: 15 }} />
                </Button>
            </View>
            {/* <View style={styles.controls}>
<View style={styles.generalControls}>

<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> */}
            <Modal
                animationType="slide"
                transparent={true}
                visible={modalVisible}
                onRequestClose={() => {
                    Alert.alert("Modal has been closed.");
                }}
            >

                <View style={styles.centeredView}>
                    <View style={styles.modalView}>
                        <View style={styles.closeModal}>
                            <Button
                                transparent
                                onPress={() => { this.setModalVisible(!modalVisible); 
}}
                            >
                                <Icon name="close" />
                            </Button>
                        </View>
                        <View>
                            <Text style={{ textAlign: 'center', fontWeight: 'bold' 
}}>Play Rate</Text>
                            <List style={{ flexDirection: 'row', justifyContent: 
'space-between', alignItems: 'center' }}>
                                {this.renderRateControl(0.25)}
                                {this.renderRateControl(0.5)}
                                {this.renderRateControl(1.0)}
                                {this.renderRateControl(1.5)}
                                {this.renderRateControl(2.0)}
                            </List>
                        </View>
                    </View>
                </View>
            </Modal>
        </View >
    )
}
}

const styles = StyleSheet.create({
backgroundVideo: {
    // position: 'absolute',
    // top: 0,
    // left: 0,
    // bottom: 0,
    // right: 0,
    width: Dimensions.get('window').width,
    height: Dimensions.get('window').width * .6,
},

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: {
    flexDirection: 'row',
    position: 'absolute',
    top: 10,
    right: 10
},
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,
},
centeredView: {
    flex: 1,
    marginTop: '22%'
},
modalView: {
    width: '100%',
    padding: '5%',
    backgroundColor: "white",
    position: 'absolute',
    bottom: 10,
},
openButton: {
    backgroundColor: "#F194FF",
    borderRadius: 20,
    padding: 10,
    elevation: 2
},
closeModal: {
    alignItems: 'flex-end',
    margin: -10
},
textStyle: {
    color: "white",
    fontWeight: "bold",
    textAlign: "center"
},
modalText: {
    marginBottom: 15,
    textAlign: "center"
}
});

我希望这能帮到您。

大多数建议涉及添加额外的库以在 react-native-vide for android 中实现全屏。它并不是真正需要的。

我们需要的是设置全屏的高度和宽度来实现这一点。我们需要使用变量而不是固定值然后 setState 来刷新视图。

以下是适用于 react-native-video 全屏的示例typescript代码:

import React, {Component} from 'react';
import {
  View,
  StyleSheet,
  TouchableWithoutFeedback,
  Dimensions,
} from 'react-native';

import Video from 'react-native-video';

import Icon from 'react-native-vector-icons/FontAwesome';
import MaterialIcon from 'react-native-vector-icons/MaterialCommunityIcons';

interface Props {}
interface States {
  paused: boolean;
  inFullScreen: boolean;
}
export default class Sandbox extends Component<Props, States> {
  player: any;
  videoStyle: {minWidth: number; minHeight: number};

  constructor(props: Props) {
    super(props);
    this.state = {
      paused: true,
      inFullScreen: false,
    };
    this.videoStyle = {minWidth: 400, minHeight: 400};
  }
  render() {
    return (
      <View style={{height: 400, width: 400}}>
        <Video
          source={{
            uri:
              'https://www.radiantmediaplayer.com/media/big-buck-bunny-360p.mp4',
          }} // Can be a URL or a local file.
          ref={(ref: any) => {
            this.player = ref;
          }} // Store reference
          controls={false}
          paused={this.state.paused}
          resizeMode={'cover'}
          style={this.videoStyle}
        />
        <View style={styles.controls}>
          <TouchableWithoutFeedback
            onPress={() => {
              this.setState({paused: !this.state.paused});
            }}>
            <Icon name={'play'} size={30} color="#FFF" />
          </TouchableWithoutFeedback>

          <TouchableWithoutFeedback
            onPress={() => {
              if (!this.state.inFullScreen) {
                //Orientation.lockToLandscape();
                this.videoStyle = {
                  minHeight: Dimensions.get('window').height,
                  minWidth: Dimensions.get('window').width,
                };
              } else {
                this.videoStyle = {
                  minHeight: 400,
                  minWidth: 400,
                };
              }

              this.setState({inFullScreen: !this.state.inFullScreen});
            }}>
            <MaterialIcon name={'fullscreen'} size={30} color="#FFF" />
          </TouchableWithoutFeedback>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  controls: {
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
    height: 48,
    top: 20,
    left: 0,
    bottom: 0,
    right: 0,
    position: 'absolute',
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-around',
    paddingHorizontal: 10,
  },
});

正如@Selva 回答的那样,我们可以使用视频大小的变量,即宽度和高度,并使其占据全屏,并使用堆栈将视频放在当前屏幕上方的堆栈屏幕中,并在需要时弹出。即使它在一个平面列表中。