Flutter中使用底部导航栏切换页面时如何暂停视频播放?
问题分析与解决方案
你的代码里在build方法中通过路由判断控制视频播放,但切换底部导航时,首页的Widget树不会重建,build方法不会重新执行,导致判断逻辑无法触发,视频也就不会自动暂停。下面是两种可行的解决方法:
方法一:监听GetX路由变化
利用GetX的路由监听功能,实时监控当前路由变化,离开首页时暂停视频,返回首页且是当前显示的视频时恢复播放。
修改后的VideoTile代码:
import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:ramadan/routes.dart'; import 'package:cached_video_player_plus/cached_video_player_plus.dart'; class VideoTile extends StatefulWidget { const VideoTile({ super.key, required this.video, required this.snappedPageIndex, required this.currentIndex, }); final dynamic video; final int snappedPageIndex; final int currentIndex; @override State<VideoTile> createState() => _VideoTileState(); } class _VideoTileState extends State<VideoTile> { late CachedVideoPlayerPlusController _cacheController; late Future _initializeVideoplayer; bool _isVideoPlaying = true; StreamSubscription<String>? _routeSubscription; @override void initState() { super.initState(); // 初始化视频控制器 _cacheController = CachedVideoPlayerPlusController.networkUrl( Uri.parse(widget.video['url']), httpHeaders: {'Connection': 'keep-alive'}, invalidateCacheIfOlderThan: const Duration(minutes: 60), ); _initializeVideoplayer = _cacheController.initialize().then((value) async { await _cacheController.setLooping(true); _cacheController.play(); setState(() {}); }); // 监听路由变化 _routeSubscription = Get.routing.listen((route) { if (route.current != AppRoutes.home) { // 离开首页时暂停视频 _cacheController.pause(); setState(() => _isVideoPlaying = false); } else if (widget.snappedPageIndex == widget.currentIndex) { // 返回首页且是当前显示的视频时恢复播放 _cacheController.play(); setState(() => _isVideoPlaying = true); } }); } @override void dispose() { // 取消路由监听,避免内存泄漏 _routeSubscription?.cancel(); _cacheController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container( color: Colors.black, child: FutureBuilder( future: _initializeVideoplayer, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return InkWell( onTap: () { // 手动点击切换播放/暂停状态 if (_isVideoPlaying) { _cacheController.pause(); } else { _cacheController.play(); } setState(() => _isVideoPlaying = !_isVideoPlaying); }, child: Stack( alignment: Alignment.center, children: [ CachedVideoPlayerPlus(_cacheController), IconButton( onPressed: () { _cacheController.play(); setState(() => _isVideoPlaying = true); }, icon: Icon( Icons.play_arrow, color: Colors.white.withOpacity(_isVideoPlaying ? 0 : 0.5), size: 60, ), ) ], ), ); } else { return Container(color: Colors.pink); } }, ), ); } }
方法二:监听页面可见性(含应用前后台处理)
如果需要同时处理应用前后台切换的情况,可以使用WidgetsBindingObserver监听页面生命周期,结合路由判断实现更全面的控制:
import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:ramadan/routes.dart'; import 'package:cached_video_player_plus/cached_video_player_plus.dart'; class VideoTile extends StatefulWidget { const VideoTile({ super.key, required this.video, required this.snappedPageIndex, required this.currentIndex, }); final dynamic video; final int snappedPageIndex; final int currentIndex; @override State<VideoTile> createState() => _VideoTileState(); } class _VideoTileState extends State<VideoTile> with WidgetsBindingObserver { late CachedVideoPlayerPlusController _cacheController; late Future _initializeVideoplayer; bool _isVideoPlaying = true; @override void initState() { super.initState(); // 添加生命周期观察者 WidgetsBinding.instance.addObserver(this); // 初始化视频控制器 _cacheController = CachedVideoPlayerPlusController.networkUrl( Uri.parse(widget.video['url']), httpHeaders: {'Connection': 'keep-alive'}, invalidateCacheIfOlderThan: const Duration(minutes: 60), ); _initializeVideoplayer = _cacheController.initialize().then((value) async { await _cacheController.setLooping(true); _cacheController.play(); setState(() {}); }); } @override void dispose() { // 移除生命周期观察者 WidgetsBinding.instance.removeObserver(this); _cacheController.dispose(); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); // 应用进入后台或 inactive 状态时暂停视频 if (state == AppLifecycleState.paused || state == AppLifecycleState.inactive) { _cacheController.pause(); setState(() => _isVideoPlaying = false); } // 应用回到前台且当前视频是显示中的,恢复播放 else if (state == AppLifecycleState.resumed && widget.snappedPageIndex == widget.currentIndex) { _cacheController.play(); setState(() => _isVideoPlaying = true); } } @override void didChangeDependencies() { super.didChangeDependencies(); // 路由变化时检查,离开首页则暂停视频 final currentRoute = Get.currentRoute; if (currentRoute != AppRoutes.home) { _cacheController.pause(); setState(() => _isVideoPlaying = false); } } @override Widget build(BuildContext context) { return Container( color: Colors.black, child: FutureBuilder( future: _initializeVideoplayer, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return InkWell( onTap: () { if (_isVideoPlaying) { _cacheController.pause(); } else { _cacheController.play(); } setState(() => _isVideoPlaying = !_isVideoPlaying); }, child: Stack( alignment: Alignment.center, children: [ CachedVideoPlayerPlus(_cacheController), IconButton( onPressed: () { _cacheController.play(); setState(() => _isVideoPlaying = true); }, icon: Icon( Icons.play_arrow, color: Colors.white.withOpacity(_isVideoPlaying ? 0 : 0.5), size: 60, ), ) ], ), ); } else { return Container(color: Colors.pink); } }, ), ); } }
核心原因
原来的代码依赖build方法触发播放/暂停判断,但底部导航切换时,首页的Widget不会重建,build方法不会执行,所以逻辑无法触发。通过主动监听路由或页面生命周期,才能实时响应页面状态变化,控制视频播放。
内容的提问来源于stack exchange,提问作者Mohammed Bekele
相关产品推荐
相关产品推荐

