使用Expo Video Player时,跳转页面如何暂停或停止视频?
Hey there! I've dealt with this exact background video playback issue using Expo Video Player and React Navigation before—let's fix it for you. Here are two solid approaches to pause/stop the video when pushing a new screen onto the stack:
Approach 1: Use Navigation Lifecycle Hooks (Class Component)
Since your code looks like a class component, we can leverage React Navigation's blur and focus events to toggle the video's play state. Here's how to modify your component:
- Add a
shouldPlaystate to control the video's playback - Attach listeners to the navigation events to update this state when the screen loses or regains focus
- Update the
VideoPlayerto use the state forshouldPlay
Here's the modified code:
import React, { Component } from 'react'; import { Video } from 'expo-av'; import VideoPlayer from 'expo-video-player'; import { ScreenOrientation } from 'expo'; class VideoScreen extends Component { state = { shouldPlay: true, }; componentDidMount() { // Listen for when the screen loses focus (when you push a new screen) this.blurListener = this.props.navigation.addListener('blur', () => { this.setState({ shouldPlay: false }); }); // Listen for when the screen regains focus (when you navigate back) this.focusListener = this.props.navigation.addListener('focus', () => { this.setState({ shouldPlay: true }); }); } componentWillUnmount() { // Clean up listeners to avoid memory leaks this.blurListener.remove(); this.focusListener.remove(); } render() { return ( <VideoPlayer videoProps={{ shouldPlay: this.state.shouldPlay, resizeMode: Video.RESIZE_MODE_CONTAIN, isMuted: false, source: { uri: this.props.navigation.state.params.video }, }} isPortrait playFromPositionMillis={0} showFullscreenButton switchToLandscape={() => ScreenOrientation.allowAsync(ScreenOrientation.Orientation.LANDSCAPE)} switchToPortrait={() => ScreenOrientation.allowAsync(ScreenOrientation.Orientation.PORTRAIT)} /> ); } } export default VideoScreen;
Approach 2: Directly Control the Video Instance (More Granular Control)
If you want more control (like stopping the video completely instead of just pausing), you can get a reference to the underlying Video component and call its playback methods directly:
- Add a ref to the
Videocomponent viavideoProps - In the
blurlistener, callpauseAsync()orstopAsync()on the video ref
Modified code snippet:
// Inside your class component state = { shouldPlay: true, }; componentDidMount() { this.blurListener = this.props.navigation.addListener('blur', async () => { // Pause the video await this.videoRef.pauseAsync(); // Or stop it entirely: // await this.videoRef.stopAsync(); this.setState({ shouldPlay: false }); }); this.focusListener = this.props.navigation.addListener('focus', () => { this.setState({ shouldPlay: true }); }); } // In the VideoPlayer's videoProps videoProps={{ shouldPlay: this.state.shouldPlay, resizeMode: Video.RESIZE_MODE_CONTAIN, isMuted: false, source: { uri: this.props.navigation.state.params.video }, ref: ref => this.videoRef = ref, // Add this line }}
Bonus: Function Component Version (With useFocusEffect)
If you ever migrate to function components, here's how you'd handle it with React Navigation's useFocusEffect hook:
import React, { useState } from 'react'; import { Video } from 'expo-av'; import VideoPlayer from 'expo-video-player'; import { ScreenOrientation } from 'expo'; import { useFocusEffect } from '@react-navigation/native'; const VideoScreen = ({ navigation }) => { const [shouldPlay, setShouldPlay] = useState(true); useFocusEffect( React.useCallback(() => { // Resume playback when screen is focused setShouldPlay(true); // Pause when screen loses focus (cleanup function) return () => setShouldPlay(false); }, []) ); return ( <VideoPlayer videoProps={{ shouldPlay, resizeMode: Video.RESIZE_MODE_CONTAIN, isMuted: false, source: { uri: navigation.params.video }, }} isPortrait playFromPositionMillis={0} showFullscreenButton switchToLandscape={() => ScreenOrientation.allowAsync(ScreenOrientation.Orientation.LANDSCAPE)} switchToPortrait={() => ScreenOrientation.allowAsync(ScreenOrientation.Orientation.PORTRAIT)} /> ); }; export default VideoScreen;
All these methods ensure that when you push a new screen onto the navigation stack, the current video pauses immediately instead of playing in the background. The first approach is great for most cases, while the second gives you more control if you need to stop the video entirely.
内容的提问来源于stack exchange,提问作者Cho Cho

