fix(home): 优化短剧列表下拉刷新体验

This commit is contained in:
Zhou Weidong committed 2026-10-22 19:11:30 +08:00
1 parent f69a27bb80
commit 7945f3ffed
8 files changed
+247 -201

No files matched your search

-6
View File
@@ -210,20 +210,14 @@ class _HomeTabsState extends State<_HomeTabs> {
void initState() {
super.initState();
logic = HomeBinding().create(widget.feedController.dramas);
widget.feedController.addListener(_onFeedChanged);
}
@override
void dispose() {
widget.feedController.removeListener(_onFeedChanged);
logic.dispose();
super.dispose();
}
void _onFeedChanged() {
if (mounted) setState(() {});
}
@override
Widget build(BuildContext context) {
return ListenableBuilder(
+83 -76
View File
@@ -152,83 +152,90 @@ class _HomeFeedGridState extends State<HomeFeedGrid> {
required HomePrimaryTab tab,
required List<HomeGridCategoryShortcut> shortcuts,
}) {
final tag = _selectedTags[tab];
final dramas = _dramasFor(tab, tag, shortcuts);
return LayoutBuilder(
builder: (context, constraints) {
final itemWidth =
(constraints.maxWidth -
AppDimens.feedPageHorizontal * 2 -
AppDimens.homeGridGap * 2) /
3;
final itemExtent =
itemWidth / AppDimens.cardCoverAspectRatio +
AppDimens.homeCardBodyExtent;
return NotificationListener<ScrollNotification>(
onNotification: _onScroll,
child: AppPullToRefresh(
key: const Key('home-grid-refresh'),
onRefresh: _refresh,
child: CustomScrollView(
key: const Key('home-grid-scroll'),
controller: _scrollControllers[tab],
physics: AppPullToRefresh.physics,
slivers: [
if (widget.feedController.loadingFirstPage)
const SliverFillRemaining(
hasScrollBody: false,
child: Center(
child: SizedBox.square(
dimension: 24,
child: CircularProgressIndicator(strokeWidth: 2),
),
),
)
else if (dramas.isEmpty)
SliverFillRemaining(
hasScrollBody: false,
child: _emptyState(l10n, tab, tag),
)
else
SliverPadding(
padding: const EdgeInsets.symmetric(
horizontal: AppDimens.feedPageHorizontal,
),
sliver: SliverGrid(
key: const Key('home-grid-cards'),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: AppDimens.homeGridGap,
mainAxisSpacing: AppDimens.homeGridRowGap,
mainAxisExtent: itemExtent,
),
delegate: SliverChildBuilderDelegate(
(context, index) => HomeFeedCard(
drama: dramas[index],
onTap: () => widget.onOpenDrama(dramas[index]),
),
childCount: dramas.length,
),
),
),
if (dramas.isNotEmpty)
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(bottom: AppDimens.spaceXl),
child: PagedListFooter(
loading: widget.feedController.loadingMore,
hasMore: widget.feedController.hasMore,
hasItems: dramas.isNotEmpty,
errorMessage: widget.feedController.lastError == null
? null
: l10n.catalogError,
onRetry: widget.feedController.loadMore,
),
),
),
],
return ListenableBuilder(
listenable: widget.feedController,
builder: (context, _) {
if (widget.feedController.loadingFirstPage) {
return const Center(
child: SizedBox.square(
dimension: 24,
child: CircularProgressIndicator(strokeWidth: 2),
),
),
);
}
final tag = _selectedTags[tab];
final dramas = _dramasFor(tab, tag, shortcuts);
return LayoutBuilder(
builder: (context, constraints) {
final itemWidth =
(constraints.maxWidth -
AppDimens.feedPageHorizontal * 2 -
AppDimens.homeGridGap * 2) /
3;
final itemExtent =
itemWidth / AppDimens.cardCoverAspectRatio +
AppDimens.homeCardBodyExtent;
return NotificationListener<ScrollNotification>(
onNotification: _onScroll,
child: AppPullToRefresh(
key: const Key('home-grid-refresh'),
onRefresh: _refresh,
child: CustomScrollView(
key: const Key('home-grid-scroll'),
controller: _scrollControllers[tab],
physics: AppPullToRefresh.physics,
slivers: [
if (dramas.isEmpty)
SliverFillRemaining(
hasScrollBody: false,
child: _emptyState(l10n, tab, tag),
)
else
SliverPadding(
padding: const EdgeInsets.symmetric(
horizontal: AppDimens.feedPageHorizontal,
),
sliver: SliverGrid(
key: const Key('home-grid-cards'),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: AppDimens.homeGridGap,
mainAxisSpacing: AppDimens.homeGridRowGap,
mainAxisExtent: itemExtent,
),
delegate: SliverChildBuilderDelegate(
(context, index) => HomeFeedCard(
drama: dramas[index],
onTap: () => widget.onOpenDrama(dramas[index]),
),
childCount: dramas.length,
),
),
),
if (dramas.isNotEmpty)
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(
bottom: AppDimens.spaceXl,
),
child: PagedListFooter(
loading: widget.feedController.loadingMore,
hasMore: widget.feedController.hasMore,
hasItems: dramas.isNotEmpty,
errorMessage:
widget.feedController.lastError == null
? null
: l10n.catalogError,
onRetry: widget.feedController.loadMore,
),
),
),
],
),
),
);
},
);
},
);