Flutter视频播放器:点击重新开始视频

5
我正在使用flutter video_player包在我的应用程序中播放短视频文件。我受到了flutter食谱的启发:播放和暂停视频
我希望用户可以点击视频以从头开始重新播放。因此,我用GestureDetector包装了VideoPlayer
我目前有以下代码:
class MyVideoPlayer extends StatefulWidget {
  final File videoFile;

  MyVideoPlayer({Key key, this.videoFile}) : super(key: key);

  @override
  _MyVideoPlayerState createState() => _MyVideoPlayerState();
}

class _MyVideoPlayerState extends State<MyVideoPlayer> {
  VideoPlayerController _controller;
  Future<void> _initializeVideoPlayerFuture;

  @override
  void initState() {
    _controller = VideoPlayerController.file(widget.videoFile);
    _initializeVideoPlayerFuture = _controller.initialize();
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _initializeVideoPlayerFuture,
      builder: (context, snapshot) {
        print(snapshot.connectionState);
        if (snapshot.connectionState == ConnectionState.done) {
          // Play video once it's loaded
          _controller.play();

          return AspectRatio(
            aspectRatio: _controller.value.aspectRatio,
            child: GestureDetector(
              onTap: () async {
                await _controller.seekTo(Duration.zero);
                _controller.play();
              },
              child: VideoPlayer(_controller),
            ),
          );
        } else {
          return CircularProgressIndicator();
        }
      },
    );
  }
}


视频文件加载后(连接状态通过done),视频播放效果很好,但是当我尝试再次点击视频重播时,它不会从头开始重新播放视频。音频开始重新播放,但视频没有重新开始播放。有任何想法吗?
编辑1
根据@marcosboaventura的建议,我尝试在setState中包装调用以触发重新构建方法:
return AspectRatio(
  aspectRatio: _controller.value.aspectRatio,
  child: GestureDetector(
    onTap: () async {
      await _controller.seekTo(Duration.zero);
      setState(() {
        _controller.play();
      });
    },
    child: VideoPlayer(_controller),
  ),
);

但是视频仍然无法回放,只有声音。还有其他的想法吗?

4个回答

7

如果视频不再播放(即视频已经完成),则在点击事件上再次调用控制器上的initialize()方法是解决我的问题的最终方法。

return AspectRatio(
  aspectRatio: _controller.value.aspectRatio,
  child: GestureDetector(
    onTap: () {
      if (!_controller.value.isPlaying) {
         setState(() {});
         _controller.initialize();
      }
    },
    child: VideoPlayer(_controller),
  ),
);

2

如果您更改了视频播放中的任何内容,您需要重新构建VideoPlayer。对于您的情况,最简单的解决方案就是使用setState调用再次触发build方法。

/// ... after some code
child: GestureDetector(
          onTap: () async {
            await _controller.seekTo(Duration.zero);
            setState( () {
              _controller.play();
            } );
          },
          child: VideoPlayer(_controller),
        ),

我尝试在setState中包装将位置重置为零并重新播放视频的调用。然而,抛出了以下异常:_MyVideoPlayerState上的setState()方法被调用,其闭包或方法返回Future。也许它被标记为“async”。我编辑了我的问题,并提供了更多关于这个尝试的细节。 - skuallpa
看一下修改后的代码。async 关键字必须放在 onTap 回调函数中,而不是 setState 回调函数中。抱歉我的错误!还有一件事情,如果视频正在播放并且用户触摸了您的 GestureDetector,您不需要再次调用 controller.play()。只需 seekTo 到开头并 setState 即可。 - Marcos Boaventura
谢谢,我也尝试过(请参见上面的编辑代码),但仍然只有声音播放,没有视频。 - skuallpa
如果您在iOS模拟器上进行测试,您将无法看到视频,只能播放音频。 - Marcos Boaventura
我知道这个问题,我正在真机上进行测试。视频只有在第一次加载时才会播放。 - skuallpa

1

你可以在 onTap 中这样做

/// get the duration of the video
 final duration = await _controller.position;

/// check if video has ended
 if (duration.inSeconds ==_controller.value.duration.inSeconds) {
 /// restart the video by setting current position to 0
    _controller.seekTo(Duration.zero);
 } else {
    _controller.value.isPlaying
        ? _controller.pause()
        : _controller.play();
 }

1

我用以下方式解决了这个问题。

GestureDetector(
    onTap() {  
    if(_controller.value.position==_controller.value.duration){
            _controller.initialize();  
       }
     }
)

_controller.value.duration 存储视频时长, _controller.value.position 存储视频实际位置,如果视频播放到结尾,则 _controller.value.position 将等于 _controller.value.duration


最佳答案!谢谢 :) - Chris
谢谢,我很感激。 - Martinho Mussamba

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接