From 9475aa49a010750d35b003e2d1125ef430c47dcd Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Sun, 13 Sep 2026 18:47:13 +0800 Subject: [PATCH] feat: 优化视频专区列表布局与沉浸体验 --- lib/pages/video/zone/video_zone_page.dart | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------ 1 file changed, 118 insertions(+), 78 deletions(-) diff --git a/lib/pages/video/zone/video_zone_page.dart b/lib/pages/video/zone/video_zone_page.dart index cf2d6bf..27d6279 100644 --- a/lib/pages/video/zone/video_zone_page.dart +++ b/lib/pages/video/zone/video_zone_page.dart @@ -1,5 +1,8 @@ +import 'dart:async'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:wow_english/common/dialogs/show_dialog.dart'; import 'package:wow_english/common/request/dao/video_dao.dart'; @@ -21,62 +24,95 @@ class _VideoZonePageState extends State { @override void initState() { super.initState(); + unawaited( + SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky), + ); _itemsFuture = VideoDao.list(); } + @override + void dispose() { + unawaited( + SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky), + ); + super.dispose(); + } + void _reload() { - setState(() => _itemsFuture = VideoDao.list()); + setState(() { + _itemsFuture = VideoDao.list(); + }); } @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.white, - appBar: const WEAppBar( - titleText: '视频专区', - centerTitle: false, - ), - body: FutureBuilder>( - future: _itemsFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } - if (snapshot.hasError) { - return _VideoLoadError(onRetry: _reload); - } - final items = snapshot.data ?? const []; - if (items.isEmpty) { - return const Center( - child: Text( - '暂无视频', - style: TextStyle(color: Color(0xFF999999), fontSize: 18), + return MediaQuery.removePadding( + context: context, + removeTop: true, + child: Scaffold( + backgroundColor: Colors.white, + appBar: const WEAppBar( + titleText: '视频专区', + centerTitle: false, + ), + body: FutureBuilder>( + future: _itemsFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } + if (snapshot.hasError) { + return _VideoLoadError(onRetry: _reload); + } + final items = snapshot.data ?? const []; + if (items.isEmpty) { + return const Center( + child: Text( + '暂无视频', + style: TextStyle(color: Color(0xFF999999), fontSize: 18), + ), + ); + } + return RefreshIndicator( + onRefresh: () async { + final future = VideoDao.list(); + setState(() => _itemsFuture = future); + await future; + }, + child: LayoutBuilder( + builder: (context, constraints) { + final horizontalPadding = 30.w; + final crossAxisSpacing = 12.w; + final cardWidth = (constraints.maxWidth - + horizontalPadding * 2 - + crossAxisSpacing * 2) / + 3; + final cardHeight = cardWidth * 9 / 16 + 5.h + 24.h; + return GridView.builder( + physics: const AlwaysScrollableScrollPhysics(), + padding: EdgeInsets.fromLTRB( + horizontalPadding, + 10.h, + horizontalPadding, + 16.h, + ), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + mainAxisSpacing: 14.h, + crossAxisSpacing: crossAxisSpacing, + mainAxisExtent: cardHeight, + ), + itemCount: items.length, + itemBuilder: (context, index) => _VideoCard( + item: items[index], + onTap: () => _openVideo(items, index), + ), + ); + }, ), ); - } - return RefreshIndicator( - onRefresh: () async { - final future = VideoDao.list(); - setState(() => _itemsFuture = future); - await future; - }, - child: GridView.builder( - physics: const AlwaysScrollableScrollPhysics(), - padding: EdgeInsets.fromLTRB(14.w, 10.h, 14.w, 16.h), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, - mainAxisSpacing: 14.h, - crossAxisSpacing: 12.w, - childAspectRatio: 1.55, - ), - itemCount: items.length, - itemBuilder: (context, index) => _VideoCard( - item: items[index], - onTap: () => _openVideo(items, index), - ), - ), - ); - }, + }, + ), ), ); } @@ -99,7 +135,13 @@ class _VideoZonePageState extends State { .toList(), 'initialVideoId': item.id, }, - ).then((_) => _reload()); + ).then((_) { + if (!mounted) return; + unawaited( + SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky), + ); + _reload(); + }); } } @@ -140,43 +182,41 @@ class _VideoCard extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( + AspectRatio( + aspectRatio: 16 / 9, child: ClipRRect( borderRadius: BorderRadius.circular(8.r), - child: Stack( - fit: StackFit.expand, - children: [ - CachedNetworkImage( - imageUrl: item.coverUrl, - fit: BoxFit.cover, - placeholder: (_, __) => const ColoredBox( - color: Color(0xFFF2F2F2), - child: Center(child: CircularProgressIndicator()), - ), - errorWidget: (_, __, ___) => const ColoredBox( - color: Color(0xFFF2F2F2), - child: Icon(Icons.broken_image_outlined, - color: Color(0xFFAAAAAA)), - ), - ), - const Center( - child: Icon(Icons.play_circle_fill, - size: 42, color: Colors.white), - ), - ], + child: CachedNetworkImage( + imageUrl: item.coverUrl, + fit: BoxFit.cover, + placeholder: (_, __) => const ColoredBox( + color: Color(0xFFF2F2F2), + child: Center(child: CircularProgressIndicator()), + ), + errorWidget: (_, __, ___) => const ColoredBox( + color: Color(0xFFF2F2F2), + child: Icon(Icons.broken_image_outlined, + color: Color(0xFFAAAAAA)), + ), ), ), ), SizedBox(height: 5.h), - Text( - item.title, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: const Color(0xFF222222), - fontFamily: null, - fontSize: 17.sp, - fontWeight: FontWeight.w500, + SizedBox( + height: 24.h, + child: Align( + alignment: Alignment.centerLeft, + child: Text( + item.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: const Color(0xFF222222), + fontFamily: null, + fontSize: 17.sp, + fontWeight: FontWeight.w500, + ), + ), ), ), ], -- libgit2 0.22.2