我的 Flutter 应用程序中有两个页面:一个
NewsTile
页面显示新闻图块列表,以及一个 ReadDetails
页面显示所选新闻项目的完整详细信息。每个 NewsTile
包含新闻的小图像,而 ReadDetails
页面显示同一图像的较大版本。
我使用
Hero
动画在 NewsTile
和 ReadDetails
页面之间转换。向前导航时,过渡效果非常好。但是,当我使用 Get.back()
(来自 GetX)或 Navigator.pop(context)
向后导航时,会出现以下问题:
NewsTile
列表中的所有图像都会重新加载,除了Hero
动画中涉及的图像(用户单击以导航到详细信息页面的图块)。该图像保持以前的状态并且不会刷新。首页
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
var dataCtrl = Get.find<DataController>();
var ctrl = Get.find<MyController>();
var dummyData = [NewsList(newsData: dataCtrl.dummyNewsData)];
return Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerTop,
floatingActionButton: const GoToTop(),
body: Obx(
() {
var topStories = dataCtrl.isDataLoaded.value
? dataCtrl.topStories.value.data!.newsList!
: dummyData;
var trendingNews = dataCtrl.isDataLoaded.value
? dataCtrl.trendingNews.value.data!.newsList!
: dummyData;
return Skeletonizer(
enableSwitchAnimation: true,
enabled: !dataCtrl.isDataLoaded.value,
child: SingleChildScrollView(
controller: ctrl.scrollController.value,
child: Column(
children: [
SectionDivider(title: 'Featured', onSeeAll: () {}),
FeaturedCard(newsList: topStories),
const SizedBox(height: 15),
SectionDivider(title: 'News', onSeeAll: () {}),
const SizedBox(height: 10),
const TopicsChip(),
const SizedBox(height: 16),
//* First page being called from here*//
//****//
const NewsTile(newsList: trendingNews),
],
),
),
);
},
),
);
}
}
第1页
具有 getx 状态管理的无状态小部件
ListView.builder(
shrinkWrap: true,
itemCount: trendingNews.length,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return nkWell(
onTap: () => Get.to(ReadDetails(newsData: newsData)),
child: Hero(
tag: '${newsData.imageUrl!}as image tag',
child: ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20),
bottomLeft: Radius.circular(20),
),
child: CachedNetworkImage(
cacheKey: newsData.imageUrl,
width: constraints.maxWidth * 0.4,
height: constraints.maxHeight,
placeholder: (_, __) => const MyShimmer(),
errorWidget: (_, __, er) => const Icon(Icons.error),
imageUrl: newsData.imageUrl!,
fit: BoxFit.cover,
),
),
),
);
},
);
第2页
也是一个具有 getx 状态管理的无状态小部件
Stack(
children: [
Hero(
tag: '${newsData.imageUrl!}as image tag',
child: ClipRRect(
borderRadius: BorderRadius.circular(15),
child: CachedNetworkImage(
height: Get.size.height / 2.5,
cacheKey: newsData.imageUrl!,
imageUrl: newsData.imageUrl!,
placeholder: (_, __) => const MyShimmer(),
errorWidget: (_, __, er) => const Icon(Icons.error),
width: Get.size.width,
fit: BoxFit.cover,
),
),
),
Positioned(
top: 4,
left: 8,
child: FloatingIconButton(
onTap: () => Get.back(),
icon: Icons.arrow_back_ios_new,
).animate().slide(delay: Durations.medium4),
),
],
);
将
AutomaticKeepAliveClientMixin
添加到 NewsTile
类:这并没有解决问题。
已添加
CachedNetworkImage
。
根据新闻项目的
Hero
和 id
,为每个图块使用独特的
imageUrl
标签:问题仍然存在。
您似乎遇到了英雄动画的常见行为。 Hero 的工作方式涉及通过三个步骤在小部件树中的不同位置移动小部件:
不幸的是,因此,返回时,英雄动画中涉及的图像不会在原始页面中刷新。发生这种情况是因为小部件被移动到覆盖层,然后又回到原始位置。
在这种情况下,使用 GlobalKey 可以帮助维护小部件状态,但 Hero 与 GlobalKey 不兼容,因此该方法在这里不起作用。
一个可能的解决方案是重构代码,以便在返回时不需要重新加载 initState 或图像。例如,您可以避免重新加载之前缓存的图像,或者研究更高级的状态管理以跨页面保留图像的状态。