react-native-video全屏弹窗时进度条异常问题求助
问题解决:React Native视频全屏Modal双实例播放冲突
问题根源
你当前代码里渲染了两个独立的<Video>组件实例,且都绑定了同一个videoPlayer ref、相同的播放状态(paused、currentTime等)和回调函数。Modal弹出时,背景的Video未停止,两个实例同时播放,各自触发onProgress更新同一个currentTime状态,导致进度条在两个实例的播放进度间来回跳动。
解决方案
核心思路是只保留一个Video实例,根据全屏状态切换它的渲染位置(原容器/Modal),而非渲染两个独立实例。具体修改步骤如下:
修改后的完整代码
import React, { useRef, useState } from 'react'; import { View, StyleSheet, TouchableOpacity, Modal, Alert, Text } from 'react-native'; import Video from 'react-native-video'; import MediaControls from 'react-native-media-controls'; const PLAYER_STATES = { PLAYING: 'playing', PAUSED: 'paused', ENDED: 'ended', }; const ChatVideoPlayerComponent = () => { const videoPlayer = useRef<any>(null); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); const [isPlayerLoading, setIsPlayerLoading] = useState(true); const [paused, setPaused] = useState(false); const [playerState, setPlayerState] = useState(PLAYER_STATES.PLAYING); const [modalVisible, setModalVisible] = useState(false); const onSeek = (seek: number) => { videoPlayer.current?.seek(seek); }; const onPaused = (state: string) => { setPaused(!paused); setPlayerState(state); }; const onReplay = () => { setPlayerState(PLAYER_STATES.PLAYING); setPaused(false); videoPlayer.current?.seek(0); }; const onProgress = (data: { currentTime: number }) => { if (!isPlayerLoading && playerState !== PLAYER_STATES.ENDED) { setCurrentTime(data.currentTime); } }; const onLoad = (data: { duration: number }) => { setDuration(data.duration); setIsPlayerLoading(false); }; const onLoadStart = () => setIsPlayerLoading(true); const onEnd = () => setPlayerState(PLAYER_STATES.ENDED); const onError = () => console.log('视频播放出错'); const toggleFullScreen = () => { setModalVisible(!modalVisible); }; const renderToolbar = () => ( <View> <Text style={styles.toolbar}> toolbar </Text> </View> ); const onSeeking = (time: number) => setCurrentTime(time); // 统一渲染视频与控制栏的复用组件 const renderVideoWithControls = (containerStyle: any) => ( <View style={{ position: 'relative', flex: 1, ...containerStyle }}> <Video ref={videoPlayer} source={{ uri: 'https://assets.mixkit.co/videos/download/mixkit-countryside-meadow-4075.mp4' }} style={styles.video} resizeMode={modalVisible ? 'cover' : 'cover'} paused={paused} onEnd={onEnd} onLoad={onLoad} onLoadStart={onLoadStart} onProgress={onProgress} onError={onError} repeat={true} volume={10} /> <MediaControls duration={duration} isLoading={isPlayerLoading} mainColor="#333" onFullScreen={toggleFullScreen} onPaused={onPaused} onReplay={onReplay} onSeek={onSeek} onSeeking={onSeeking} playerState={playerState} progress={currentTime} toolbar={renderToolbar()} /> </View> ); return ( <View style={styles.container}> {/* 非全屏状态下的视频 */} {!modalVisible && renderVideoWithControls({ width: 200, height: 200 })} {/* 全屏Modal */} <Modal animationType="slide" transparent={true} visible={modalVisible} onRequestClose={() => { Alert.alert('Modal已关闭'); toggleFullScreen(); }} > <View style={styles.modalContainer}> <View style={styles.modalContent}> <TouchableOpacity style={styles.closeBtn} onPress={toggleFullScreen}> <Text style={styles.closeTxt}>×</Text> </TouchableOpacity> {/* 全屏状态下的视频 */} {renderVideoWithControls({ width: '100%' })} </View> </View> </Modal> </View> ); }; const styles = StyleSheet.create({ container: { justifyContent: 'flex-start', }, video: { width: '100%', height: '100%', }, toolbar: { marginTop: 30, backgroundColor: 'red', padding: 10, borderRadius: 5, }, modalContainer: { flex: 1, justifyContent: 'center', backgroundColor: '#000000A0', }, modalContent: { marginHorizontal: 10, backgroundColor: 'white', borderRadius: 20, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 4, elevation: 5, flex: 1, }, closeBtn: { alignSelf: 'flex-end', padding: 15, }, closeTxt: { fontSize: 24, color: '#333', }, }); export default ChatVideoPlayerComponent;
关键修改说明
- 移除重复的
<Video>和<MediaControls>实例,通过renderVideoWithControls函数统一渲染,彻底避免双实例冲突。 - 用
toggleFullScreen简化全屏切换逻辑,仅控制Modal显示状态,删除冗余的screenType等状态管理。 - 两个状态下的视频共用同一个
videoPlayerref,确保播放进度、暂停状态完全同步。 - 优化Modal关闭逻辑,保持播放状态的一致性。
内容的提问来源于stack exchange,提问作者pratteek shaurya
相关产品推荐
相关产品推荐

