Browse Source

优化视频播放全屏

盐城新淘科技有限公司 1 tuần trước cách đây
mục cha
commit
27c4af3ad1

+ 6 - 1
xinhuaribao/.claude/settings.local.json

@@ -21,7 +21,12 @@
       "Bash(rm -rf ios/Pods ios/Podfile.lock ios/.symlinks ios/Flutter/.last_build_id)",
       "Bash(git checkout:*)",
       "Bash(git add:*)",
-      "Bash(git commit:*)"
+      "Bash(git commit:*)",
+      "Bash(adb devices:*)",
+      "Read(//Users/user/Library/Android/sdk/platform-tools/**)",
+      "Read(//Users/user/Android/Sdk/platform-tools/**)",
+      "Bash(~/Library/Android/sdk/platform-tools/adb devices:*)",
+      "Bash(nc localhost:*)"
     ]
   }
 }

+ 15 - 8
xinhuaribao/lib/ui/video/video_detail_page.dart

@@ -261,11 +261,12 @@ class _VideoDetailPageState extends ConsumerState<VideoDetailPage>
           );
         },
         autoPlay: true,
-        aspectRatio: 16 / 9,
-        fit: BoxFit.fitWidth,
+        aspectRatio: 9 / 16, // 使用竖屏宽高比
+        fit: BoxFit.cover,
         controlsConfiguration: const BetterPlayerControlsConfiguration(
           showControls: false,
         ),
+        handleLifecycle: false,
       ),
       betterPlayerDataSource: dataSource,
     );
@@ -275,6 +276,16 @@ class _VideoDetailPageState extends ConsumerState<VideoDetailPage>
       consoleLog("VideoDetailPage: BetterPlayerEvent: ${event.betterPlayerEventType}");
       if (event.betterPlayerEventType == BetterPlayerEventType.play) {
         consoleLog("VideoDetailPage: Video started playing");
+      } else if (event.betterPlayerEventType == BetterPlayerEventType.exception) {
+        consoleLog("VideoDetailPage: Exception occurred, attempting to replay...");
+        _betterPlayerController?.pause();
+        Future.delayed(const Duration(milliseconds: 500), () {
+          _betterPlayerController?.play();
+        });
+      } else if (event.betterPlayerEventType == BetterPlayerEventType.bufferingStart) {
+        consoleLog("VideoDetailPage: Buffering started");
+      } else if (event.betterPlayerEventType == BetterPlayerEventType.bufferingEnd) {
+        consoleLog("VideoDetailPage: Buffering ended");
       }
     });
 
@@ -292,12 +303,8 @@ class _VideoDetailPageState extends ConsumerState<VideoDetailPage>
         alignment: Alignment.centerRight,
         children: [
           if (_betterPlayerController != null)
-            ColoredBox(
-              color: Colors.black,
-              child: AspectRatio(
-                aspectRatio: 16 / 9,
-                child: BetterPlayer(controller: _betterPlayerController!),
-              ),
+            Center(
+              child: BetterPlayer(controller: _betterPlayerController!),
             )
           else
             Center(

+ 52 - 12
xinhuaribao/lib/ui/video/video_play_item_widget.dart

@@ -1,3 +1,4 @@
+import 'dart:async';
 import 'dart:io';
 
 import 'package:better_player_plus/better_player_plus.dart';
@@ -35,8 +36,9 @@ class VideoPlayItemWidget extends ConsumerStatefulWidget {
 }
 
 class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget>
-    with AutomaticKeepAliveClientMixin {
+    with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin {
   bool _isPlaying = false;
+  late Timer _playStateCheckTimer;
 
   bool _isWeChatInstalled = false;
 
@@ -117,7 +119,7 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget>
                             width: 100.w,
                             height: 80.h,
                             child: Column(
-                              mainAxisAlignment: CrossAxisAlignment.center,
+                              mainAxisAlignment: MainAxisAlignment.center,
                               children: [
                                 LoadAssetImage(
                                   'share_pyq',
@@ -179,6 +181,34 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget>
     super.initState();
     consoleLog("VideoPlayItemWidget: initState for video ${widget.item.contentId}, url: ${widget.item.url}, isActive: ${widget.isActive}");
     _checkWeChatInstallation();
+    _startPlayStateCheck();
+  }
+
+  void _startPlayStateCheck() {
+    // 定期检查视频播放状态
+    _playStateCheckTimer = Timer.periodic(const Duration(milliseconds: 500), (_) {
+      if (!mounted) {
+        _playStateCheckTimer.cancel();
+        return;
+      }
+      final controller = globalVideoController;
+      if (controller != null && widget.isActive) {
+        final isPlaying = controller.isPlaying() ?? false;
+
+        // 更新播放状态
+        if (isPlaying != _isPlaying) {
+          setState(() {
+            _isPlaying = isPlaying;
+          });
+        }
+      }
+    });
+  }
+
+  @override
+  void dispose() {
+    _playStateCheckTimer.cancel();
+    super.dispose();
   }
 
   void _togglePlay() {
@@ -190,12 +220,20 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget>
     if (_isPlaying) {
       try {
         controller.pause();
+        // 立即更新状态
+        setState(() {
+          _isPlaying = false;
+        });
       } catch (e) {
         // 控制器可能已被释放,忽略错误
       }
     } else {
       try {
         controller.play();
+        // 立即更新状态
+        setState(() {
+          _isPlaying = true;
+        });
       } catch (e) {
         // 控制器可能已被释放,忽略错误
       }
@@ -212,16 +250,18 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget>
       child: Stack(
         fit: StackFit.expand,
         children: [
-          ColoredBox(
-            color: Colors.black,
-            child: controller != null && widget.isActive
-                ? AspectRatio(
-                    aspectRatio: 16 / 9,
-                    child: BetterPlayer(controller: controller),
-                  )
-                : const SizedBox.shrink(),
-          ),
-          if (!_isPlaying && widget.isActive && controller != null)
+          // 黑色背景
+          const ColoredBox(color: Colors.black),
+
+          // 视频播放器(只在当前页激活时显示)
+          if (controller != null && widget.isActive)
+            BetterPlayer(
+              key: ValueKey('video_${widget.item.contentId}'),
+              controller: controller,
+            ),
+
+          // 播放按钮(只在视频暂停时显示)
+          if (!_isPlaying && widget.isActive)
             Center(
               child: Image.asset(
                 Assets.images.playIcon.path,

+ 39 - 10
xinhuaribao/lib/ui/video/video_recommend_list_page.dart

@@ -50,8 +50,11 @@ class _VideoRecommendListPageState extends ConsumerState<VideoRecommendListPage>
     if (controller == null) return;
 
     try {
-      operation();
+      if (controller.isVideoInitialized() == true) {
+        operation();
+      }
     } catch (e) {
+      consoleLog("Controller operation error: $e");
       // 控制器可能已被释放,重置为 null
       globalVideoController = null;
     }
@@ -76,14 +79,29 @@ class _VideoRecommendListPageState extends ConsumerState<VideoRecommendListPage>
       BetterPlayerConfiguration(
         autoPlay: true,
         looping: true,
-        aspectRatio: 16 / 9,
-        fit: BoxFit.fitWidth,
+        fit: BoxFit.fitWidth, // 宽度固定,高度自适应
         controlsConfiguration: const BetterPlayerControlsConfiguration(
           showControls: false,
         ),
+        handleLifecycle: false,
+        autoDetectFullscreenAspectRatio: false,
+        errorBuilder: (context, errorMessage) {
+          consoleLog("GlobalVideoController error: $errorMessage");
+          // 返回空 widget,不显示错误
+          return const SizedBox.shrink();
+        },
       ),
     );
 
+    // 先添加事件监听,然后再设置数据源
+    globalVideoController!.addEventsListener((event) {
+      consoleLog("GlobalVideoController event: ${event.betterPlayerEventType}");
+      if (event.betterPlayerEventType == BetterPlayerEventType.exception) {
+        consoleLog("Video exception occurred");
+        // 静默处理异常
+      }
+    });
+
     Future.delayed(const Duration(milliseconds: 50), () {
       if (!mounted || globalVideoController == null) return;
 
@@ -92,6 +110,9 @@ class _VideoRecommendListPageState extends ConsumerState<VideoRecommendListPage>
           BetterPlayerDataSourceType.network,
           url,
           videoFormat: BetterPlayerVideoFormat.other,
+          notificationConfiguration: BetterPlayerNotificationConfiguration(
+            showNotification: false,
+          ),
         );
 
         globalVideoController!.setupDataSource(dataSource).then((_) {
@@ -101,10 +122,12 @@ class _VideoRecommendListPageState extends ConsumerState<VideoRecommendListPage>
             });
           }
         }).catchError((error) {
-          globalVideoController = null;
+          consoleLog("Video setup error: $error");
+          // 静默处理错误,不显示错误提示
         });
       } catch (e) {
-        globalVideoController = null;
+        consoleLog("Video play error: $e");
+        // 静默处理错误,不显示错误提示
       }
     });
   }
@@ -112,7 +135,8 @@ class _VideoRecommendListPageState extends ConsumerState<VideoRecommendListPage>
   @override
   void dispose() {
     _pageController.dispose();
-    // 不在这里 dispose 全局控制器
+    // 暂停播放但不dispose,因为可能被其他页面使用
+    globalVideoController?.pause();
     super.dispose();
   }
 
@@ -128,13 +152,18 @@ class _VideoRecommendListPageState extends ConsumerState<VideoRecommendListPage>
     }
     if (visible) {
       consoleLog("页面可见");
-      _safeControllerOperation(() {
-        globalVideoController!.play();
-      });
+      // 页面重新可见时,重新初始化视频以确保状态正确
+      final videos = ref.read(recommendListProvider);
+      if (videos.isNotEmpty && _currentPageIndex < videos.length) {
+        final url = videos[_currentPageIndex].url;
+        if (url != null && url.isNotEmpty) {
+          _playVideo(url);
+        }
+      }
     } else {
       consoleLog("页面不可见");
       _safeControllerOperation(() {
-        globalVideoController!.pause();
+        globalVideoController?.pause();
       });
     }
   }