You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中Expo VideoPlayer全屏保留自定义控件问题咨询

React Native视频全屏时自定义控件消失问题

我在开发React Native应用时,希望实现视频播放并支持全屏功能。加载组件时一切正常,但进入全屏后,我添加的自定义控件会消失,取而代之的是系统默认控件。以下是我的代码:

import React, { useState, useRef } from "react";
import {
    View,
    StyleSheet,
    Dimensions,
    Text,
} from "react-native";
import { ResizeMode } from "expo-av";
import GeneralStyles from "../../styles/GeneralStyles";
import { LinearGradient } from "expo-linear-gradient";
import { ScrollView } from "react-native-gesture-handler";
import VideoPlayer from "expo-video-player";

const MyComponent = () => {
    const lastVideo = useRef(null);

    const [fullScreenMode, setFullScreenMode] = useState(ResizeMode.COVER);

    const { width } = Dimensions.get("window");

    return (
        <LinearGradient colors={["#FFFFFF", "#FFEFE3", "#FFE1E1", "#FFFFFF"]}>
            <ScrollView style={GeneralStyles.mainContainer}>
                <View style={[styles.videoContainer]}>
                    <View style={{ padding: 10, borderWidth: 1, backgroundColor: 'black', borderRadius: 10 }}>
                        <VideoPlayer
                            videoProps={{
                                shouldPlay: false,
                                resizeMode: fullScreenMode,
                                source: {
                                    uri: "https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4",
                                },
                                ref: lastVideo,
                            }}
                            style={{
                                height: width * 1.5,
                                width: width * 0.9,
                                videoBackgroundColor: "transparent",
                                controlsBackgroundColor: "black",
                            }}
                            header={
                                <Text style={{ color: "#FFF", padding: 10 }}>
                                    The title
                                </Text>
                            }
                            autoHidePlayer={{ autoHide: true, duration: 1000 }}
                            activityIndicator={{ size: "large", color: "#FFF" }}
                            slider={{
                                thumbTintColor: "#FFF",
                                margin: 10,
                                minimumTrackTintColor: "#E50000",
                                maximumTrackTintColor: "#FFF",
                            }}
                            fullscreen={{
                                visible: true,
                                enterFullscreen: async () => {
                                    try {
                                        setFullScreenMode(ResizeMode.CONTAIN);
                                        await lastVideo.current.presentFullscreenPlayer();
                                    } catch (error) {
                                        console.log(error);
                                    }
                                },
                                exitFullscreen: async () => {
                                    try {
                                        setFullScreenMode(ResizeMode.COVER);
                                        await lastVideo.current.dismissFullscreenPlayer();
                                    } catch (error) {
                                        console.log(error);
                                    }
                                },
                                controls: {
                                    hide: true,
                                },
                            }}
                        />
                    </View>
                    <View style={styles.dateContainer}>
                        <Text style={styles.date}>17/06/2023</Text>
                    </View>
                </View>
            </ScrollView>
        </LinearGradient>
    );
};

const styles = StyleSheet.create({
    videoContainer: {
        alignSelf: "center",
        marginBottom: 20,
    },
    date: {
        fontSize: 15,
        textAlign: "center",
        fontWeight: 300,
        color: "rgba(255, 255, 255, 1)",
        padding: 5,
        paddingLeft: 10,
    },
    dateContainer: {
        position: "absolute",
        top: 10,
        right: 10,
        width: "auto",
        justifyContent: "center",
        alignItems: "center",
        backgroundColor: "rgba(0, 0, 0, 0.7)",
        borderRadius: 10,
    },
});

我了解到使用presentFullscreenPlayer()时,即使设置useNativeControls为false,仍会使用默认控件。请问如何让自定义控件在全屏时显示?是否需要更换库,或者有其他解决方法?


解决方案

方法1:手动实现"伪全屏",规避系统原生全屏API

系统的presentFullscreenPlayer()会强制接管视频渲染并使用原生控件,这是Expo Video的固有限制。可以通过调整组件布局模拟全屏效果:

  • 新增isFullScreen状态控制页面元素显示
  • 进入全屏时:
    • 锁定屏幕为横向(需借助expo-screen-orientation库)
    • 隐藏ScrollView及其他非视频元素
    • 将视频容器设为占满整个屏幕
  • 退出全屏时恢复原有布局与屏幕方向

核心修改代码示例:

import { ScreenOrientation } from 'expo-screen-orientation';

const MyComponent = () => {
    const lastVideo = useRef(null);
    const [fullScreenMode, setFullScreenMode] = useState(ResizeMode.COVER);
    const [isFullScreen, setIsFullScreen] = useState(false);
    const { width, height } = Dimensions.get("window");

    const enterFullscreen = async () => {
        try {
            await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE_LEFT);
            setFullScreenMode(ResizeMode.CONTAIN);
            setIsFullScreen(true);
            // 保持视频播放状态
            await lastVideo.current.playAsync();
        } catch (error) {
            console.log(error);
        }
    };

    const exitFullscreen = async () => {
        try {
            await ScreenOrientation.unlockAsync();
            setFullScreenMode(ResizeMode.COVER);
            setIsFullScreen(false);
            await lastVideo.current.pauseAsync();
        } catch (error) {
            console.log(error);
        }
    };

    return (
        <LinearGradient colors={["#FFFFFF", "#FFEFE3", "#FFE1E1", "#FFFFFF"]}>
            {!isFullScreen ? (
                <ScrollView style={GeneralStyles.mainContainer}>
                    <View style={[styles.videoContainer]}>
                        <View style={{ padding: 10, borderWidth: 1, backgroundColor: 'black', borderRadius: 10 }}>
                            <VideoPlayer
                                videoProps={{
                                    shouldPlay: false,
                                    resizeMode: fullScreenMode,
                                    source: { uri: "https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4" },
                                    ref: lastVideo,
                                    useNativeControls: false
                                }}
                                style={{ height: width * 1.5, width: width * 0.9 }}
                                header={<Text style={{ color: "#FFF", padding: 10 }}>The title</Text>}
                                autoHidePlayer={{ autoHide: true, duration: 1000 }}
                                activityIndicator={{ size: "large", color: "#FFF" }}
                                slider={{
                                    thumbTintColor: "#FFF",
                                    margin: 10,
                                    minimumTrackTintColor: "#E50000",
                                    maximumTrackTintColor: "#FFF",
                                }}
                                fullscreen={{
                                    visible: true,
                                    enterFullscreen,
                                    exitFullscreen
                                }}
                            />
                        </View>
                        <View style={styles.dateContainer}>
                            <Text style={styles.date}>17/06/2023</Text>
                        </View>
                    </View>
                </ScrollView>
            ) : (
                <View style={{ flex: 1, backgroundColor: 'black' }}>
                    <VideoPlayer
                        videoProps={{
                            shouldPlay: true,
                            resizeMode: fullScreenMode,
                            source: { uri: "https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4" },
                            ref: lastVideo,
                            useNativeControls: false
                        }}
                        style={{ flex: 1 }}
                        header={<Text style={{ color: "#FFF", padding: 10 }}>The title</Text>}
                        autoHidePlayer={{ autoHide: true, duration: 1000 }}
                        activityIndicator={{ size: "large", color: "#FFF" }}
                        slider={{
                            thumbTintColor: "#FFF",
                            margin: 10,
                            minimumTrackTintColor: "#E50000",
                            maximumTrackTintColor: "#FFF",
                        }}
                        fullscreen={{
                            visible: true,
                            exitFullscreen
                        }}
                    />
                </View>
            )}
        </LinearGradient>
    );
};

方法2:更换视频播放库

若不想手动实现伪全屏,可选择支持自定义全屏的第三方库:

  • react-native-video:完全自定义控件与全屏逻辑,不依赖系统原生全屏API,灵活性更高
  • react-native-video-player:基于react-native-video封装,自带全屏和自定义控件能力

注意:react-native-video在Expo项目中需使用兼容版本或配合expo-av适配。

关键注意事项

  • 必须在videoProps中设置useNativeControls: false,彻底禁用原生控件
  • 伪全屏方案需配置expo-screen-orientation权限,处理屏幕方向的锁定与恢复
  • 切换全屏时需保持视频播放状态,可通过playAsync()/pauseAsync()控制

内容的提问来源于stack exchange,提问作者DFG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 11:43:17