import 'package:better_player_plus/better_player_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:news_app/constant/size_res.dart'; import 'package:news_app/ui/video/video_play_item_widget.dart'; import 'package:news_app/util/log.util.dart'; import 'package:visibility_detector/visibility_detector.dart'; import '../../model/video_new_model.dart'; import '../../provider/video_commend_provider.dart'; /// @author: bo.zeng /// @email: cnhbwds@gmail.com /// @date: 2025 2025/4/9 16:00 /// @description: class VideoRecommendListPage extends ConsumerStatefulWidget { const VideoRecommendListPage({super.key}); @override ConsumerState createState() => _VideoRecommendListPageState(); } final recommendListProvider = NotifierProvider>(() { return VideoRecommendProvider(); }); // 全局共享的视频控制器 BetterPlayerController? globalVideoController; class _VideoRecommendListPageState extends ConsumerState with AutomaticKeepAliveClientMixin { late final PageController _pageController; int _currentPageIndex = 0; String? _currentVideoUrl; @override void initState() { super.initState(); _pageController = PageController(); // 先获取视频数据 ref.read(recommendListProvider.notifier).fetchRecommendVideos(); } // 安全地执行控制器操作 void _safeControllerOperation(VoidCallback operation) { if (!mounted) return; final controller = globalVideoController; if (controller == null) return; try { operation(); } catch (e) { // 控制器可能已被释放,重置为 null globalVideoController = null; } } void _playVideo(String url) { if (!mounted) return; // 如果是同一个视频,不需要重新加载 if (_currentVideoUrl == url && globalVideoController != null) { _safeControllerOperation(() { globalVideoController!.play(); }); return; } _currentVideoUrl = url; // 创建新控制器 globalVideoController = null; // 释放旧的 globalVideoController = BetterPlayerController( BetterPlayerConfiguration( autoPlay: true, looping: true, aspectRatio: 16 / 9, fit: BoxFit.fitWidth, controlsConfiguration: const BetterPlayerControlsConfiguration( showControls: false, ), ), ); Future.delayed(const Duration(milliseconds: 50), () { if (!mounted || globalVideoController == null) return; try { final dataSource = BetterPlayerDataSource( BetterPlayerDataSourceType.network, url, videoFormat: BetterPlayerVideoFormat.other, ); globalVideoController!.setupDataSource(dataSource).then((_) { if (mounted && globalVideoController != null) { _safeControllerOperation(() { globalVideoController!.play(); }); } }).catchError((error) { globalVideoController = null; }); } catch (e) { globalVideoController = null; } }); } @override void dispose() { _pageController.dispose(); // 不在这里 dispose 全局控制器 super.dispose(); } bool _isVisible = false; void _onVisibilityChanged(VisibilityInfo info) { if (!mounted) return; final visible = info.visibleFraction > 0.5; if (_isVisible != visible) { setState(() { _isVisible = visible; }); } if (visible) { consoleLog("页面可见"); _safeControllerOperation(() { globalVideoController!.play(); }); } else { consoleLog("页面不可见"); _safeControllerOperation(() { globalVideoController!.pause(); }); } } void _onPageChanged(int index) { if (!mounted) return; setState(() { _currentPageIndex = index; }); // 页面切换后,播放新视频 final videos = ref.read(recommendListProvider); if (videos.isNotEmpty && index >= 0 && index < videos.length) { final url = videos[index].url; if (url != null && url.isNotEmpty) { _playVideo(url); } } } @override Widget build(BuildContext context) { super.build(context); final videos = ref.watch(recommendListProvider); // 初始化控制器并播放第一个视频 if (videos.isNotEmpty && globalVideoController == null) { WidgetsBinding.instance.addPostFrameCallback((_) { final firstUrl = videos.firstOrNull?.url; if (firstUrl != null && firstUrl.isNotEmpty && mounted) { _playVideo(firstUrl); } }); } // 视频列表为空时显示加载状态 if (videos.isEmpty) { return const Center( child: CircularProgressIndicator(), ); } return VisibilityDetector( key: const Key("value"), onVisibilityChanged: _onVisibilityChanged, child: Padding( padding: EdgeInsets.symmetric( horizontal: horizontalPadding, vertical: horizontalPadding, ), child: PageView.builder( controller: _pageController, onPageChanged: _onPageChanged, scrollDirection: Axis.vertical, itemCount: videos.length, itemBuilder: (context, index) { // 添加边界检查 if (index < 0 || index >= videos.length) { return const SizedBox.shrink(); } final item = videos[index]; return VideoPlayItemWidget( key: ValueKey("video_${item.contentId ?? index}"), item: item, isActive: _isVisible && _currentPageIndex == index, index: index, ); }, ), ), ); } @override bool get wantKeepAlive => true; }