如何使用Flutter实现类似YouTube的迷你播放器功能?
基于better_player实现YouTube式迷你播放器(避免全屏销毁问题)的解决方案
你遇到的全屏时视频销毁问题,本质是两个核心冲突:
- 通用mini player包默认在页面路由跳转时会释放子组件,而better_player默认全屏逻辑是push新的全屏路由,导致原播放器实例被销毁
- 视频状态没有和UI层做分离,播放器实例绑定了组件生命周期
第一步:改造better_player全屏逻辑,禁用默认路由跳转
不要用better_player自带的全屏切换逻辑,自己控制全屏状态,配置BetterPlayerConfiguration时关闭内置全屏:
BetterPlayerConfiguration( // 禁用内置全屏,避免路由跳转导致的实例销毁 fullScreenByDefault: false, allowedScreenSleep: false, autoDetectFullscreenDeviceOrientation: false, // 配置播放器可见性行为 playerVisibilityChangedBehavior: (visibleFraction) { // 迷你播放器收起时可以按需配置是否暂停,不要默认销毁实例 }, )
第二步:用Stack结合状态管理实现三级播放状态布局
不要依赖第三方mini player包,自己基于Stack布局实现三种播放状态共用同一个播放器实例,完全避免组件重建销毁:
- 根页面用Stack结构,播放器组件始终放在Stack最顶层,仅修改它的位置、尺寸参数,不触发组件生命周期的销毁重建
- 用全局状态(Provider、Bloc、GetX均可)维护当前播放状态:
isFullScreen、isMiniPlayer、当前播放视频ID、播放进度等 - 切全屏时,直接修改播放器尺寸为屏幕全屏,同时隐藏底部导航、页面其他内容,不要做路由跳转
- 切迷你播放器时,修改播放器尺寸为右下角小窗尺寸,底层页面可正常响应交互
第三步:配置播放器实例保活
如果播放器放在PageView或者TabView中,给播放器组件加AutomaticKeepAliveClientMixin,避免切换页面时被销毁:
class CustomVideoPlayer extends StatefulWidget { const CustomVideoPlayer({super.key}); @override State<CustomVideoPlayer> createState() => _CustomVideoPlayerState(); } class _CustomVideoPlayerState extends State<CustomVideoPlayer> with AutomaticKeepAliveClientMixin { late BetterPlayerController _betterPlayerController; @override bool get wantKeepAlive => true; // 开启组件保活 @override void initState() { super.initState(); // 初始化控制器,建议将控制器实例放到全局状态中管理,不要仅存在当前组件的state里,避免组件销毁时控制器被释放 } @override Widget build(BuildContext context) { super.build(context); // 返回播放器布局 } }
第四步:全屏切换逻辑实现
void toggleFullScreen() { final playState = globalPlayState; if (playState.isFullScreen) { // 退出全屏:恢复系统状态栏,修改播放器尺寸为普通/迷你尺寸 SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); playState.isFullScreen = false; } else { // 进入全屏:隐藏系统状态栏,设置播放器尺寸为全屏 SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); playState.isFullScreen = true; } // 通知UI更新即可,整个过程播放器实例完全不变,不会出现视频销毁的问题 }
内容的提问来源于stack exchange,提问作者Anil Poudyal
相关产品推荐
相关产品推荐

