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

Expo AV实现视频播放完毕自动回到起始位置的问题

Expo AV视频播放完毕自动回到起始位置的解决方案

问题分析

你的代码有几个关键问题导致重启功能失效:

  • 错误的状态访问:你试图通过video.status获取播放状态,但video是React ref,播放状态存在你定义的status状态变量里,应该用status.didJustFinish。
  • 错误的函数执行时机:直接在组件顶层调用restart(),会在每次组件渲染时执行,初始阶段status是空对象,video.current也可能未完成初始化,无法正确触发逻辑。
  • 未利用播放状态更新回调:Expo AV的onPlaybackStatusUpdate是专门用来监听播放状态变化的,应该在这里处理播放完成的逻辑,而不是单独调用函数。

修正后的代码

import React from 'react';
import { View, TouchableOpacity, StyleSheet } from 'react-native';
import { Video, ResizeMode } from 'expo-av';
import AntDesign from '@expo/vector-icons/AntDesign';

export default function App() {
  const video = React.useRef(null);
  const [status, setStatus] = React.useState({});

  const handlePlaybackUpdate = (newStatus) => {
    setStatus(newStatus);
    // 当视频播放完成且未开启循环时,重置到起始位置
    if (newStatus.didJustFinish && !newStatus.isLooping) {
      // 重置到视频开头
      video.current?.seekAsync(0);
      // 如果需要重置后自动暂停,保留这行;如果要自动重播,换成playFromPositionAsync(0)
      video.current?.pauseAsync();
    }
  };

  return (
    <View style={styles.container}>
      <Video
        ref={video}
        style={styles.video}
        source={require("./assets/big_buck_bunny.mp4")}
        useNativeControls={false}
        volume={1.0}
        resizeMode={ResizeMode.CONTAIN}
        isLooping={false}
        onPlaybackStatusUpdate={handlePlaybackUpdate}
      />
      <View style={styles.buttons}>
        <TouchableOpacity 
          onPress={() => {
            if (status.isPlaying) {
              video.current?.pauseAsync();
            } else {
              video.current?.playAsync();
            }
          }}
        >
          {status.isPlaying ? (
            <AntDesign style={styles.icons} name="pause" size={50} color="white" />
          ) : (
            <AntDesign style={styles.icons} name="play" size={50} color="white" />
          )}
        </TouchableOpacity>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#000',
  },
  video: {
    width: '100%',
    height: '80%',
  },
  buttons: {
    marginTop: 20,
  },
  icons: {
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.5,
    shadowRadius: 3,
  },
});

关键修改说明

  • 合并状态逻辑:把播放状态更新和完成后的重置逻辑放到handlePlaybackUpdate里,确保每次状态变化都能检查是否播放完成。
  • 选择合适的重置方法:seekAsync(0)只会把视频拉到起始位置,不会自动播放;如果需要播放完成后自动重播,换成playFromPositionAsync(0)即可。
  • 增加健壮性:用?.可选链操作符避免video.current未初始化时调用方法报错。
  • 移除无效调用:删掉组件顶层的restart()调用,所有逻辑都在状态回调中处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:08:11