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

Flutter双视频互斥播放控制:播放时另一视频自动暂停及图标切换

实现双视频互斥播放及图标同步

核心思路

将两个视频的播放状态、控制器统一放在父组件中管理,通过状态变量跟踪当前播放的视频索引,触发播放时自动暂停另一个视频,同时同步更新播放/暂停图标。

具体实现步骤

1. 父组件中管理控制器与播放状态

在包含两个PageViewWidg的页面组件里,初始化两个VideoPlayerController,并维护currentPlayingIndex变量记录当前播放的视频下标(null表示都暂停)。

class DoubleVideoPage extends StatefulWidget {
  final String videoUrl1;
  final String videoUrl2;

  const DoubleVideoPage({super.key, required this.videoUrl1, required this.videoUrl2});

  @override
  State<DoubleVideoPage> createState() => _DoubleVideoPageState();
}

class _DoubleVideoPageState extends State<DoubleVideoPage> {
  late VideoPlayerController _controller1;
  late VideoPlayerController _controller2;
  int? _currentPlayingIndex; // 0:第一个视频,1:第二个视频,null:都暂停

  @override
  void initState() {
    super.initState();
    // 初始化视频控制器
    _controller1 = VideoPlayerController.networkUrl(Uri.parse(widget.videoUrl1))
      ..initialize().then((_) => setState(() {}));
    _controller2 = VideoPlayerController.networkUrl(Uri.parse(widget.videoUrl2))
      ..initialize().then((_) => setState(() {}));
  }

  @override
  void dispose() {
    // 释放控制器避免内存泄漏
    _controller1.dispose();
    _controller2.dispose();
    super.dispose();
  }
}

2. 实现互斥播放逻辑

添加播放/暂停切换方法,点击某个视频时,先暂停另一个视频,再切换当前视频的播放状态,同步更新currentPlayingIndex:

void _togglePlay(int index) {
  setState(() {
    if (_currentPlayingIndex == index) {
      // 点击的是正在播放的视频,执行暂停
      index == 0 ? _controller1.pause() : _controller2.pause();
      _currentPlayingIndex = null;
    } else {
      // 先暂停之前播放的视频
      if (_currentPlayingIndex == 0) _controller1.pause();
      if (_currentPlayingIndex == 1) _controller2.pause();
      // 播放当前点击的视频
      index == 0 ? _controller1.play() : _controller2.play();
      _currentPlayingIndex = index;
    }
  });
}

3. 修改PageViewWidg接收外部状态与回调

让PageViewWidg不再单独管理控制器,改为接收外部传入的控制器、播放状态和点击回调:

class PageViewWidg extends StatelessWidget {
  final VideoPlayerController controller;
  final bool isPlaying;
  final VoidCallback onTogglePlay;

  const PageViewWidg({
    super.key,
    required this.controller,
    required this.isPlaying,
    required this.onTogglePlay,
  });

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTogglePlay,
      child: Stack(
        alignment: Alignment.center,
        children: [
          // 视频渲染区域
          controller.value.isInitialized
              ? AspectRatio(
                  aspectRatio: controller.value.aspectRatio,
                  child: VideoPlayer(controller),
                )
              : const Center(child: CircularProgressIndicator()),
          // 播放/暂停图标
          if (!controller.value.isPlaying || !controller.value.isInitialized)
            Icon(
              isPlaying ? Icons.pause_circle : Icons.play_circle,
              size: 60,
              color: Colors.white,
            ),
        ],
      ),
    );
  }
}

4. 父组件中挂载修改后的PageViewWidg

将两个PageViewWidg传入对应的控制器、播放状态和回调:

@override
Widget build(BuildContext context) {
  return Column(
    children: [
      Expanded(
        child: PageViewWidg(
          controller: _controller1,
          isPlaying: _currentPlayingIndex == 0,
          onTogglePlay: () => _togglePlay(0),
        ),
      ),
      Expanded(
        child: PageViewWidg(
          controller: _controller2,
          isPlaying: _currentPlayingIndex == 1,
          onTogglePlay: () => _togglePlay(1),
        ),
      ),
    ],
  );
}

关键注意点

  • 生命周期管理:必须在父组件的dispose方法中释放两个控制器,防止内存泄漏
  • 状态一致性:通过_currentPlayingIndex统一控制播放状态,确保图标显示与实际播放状态同步
  • 初始化判断:等待控制器初始化完成后再渲染视频,避免出现异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 20:50:29