导航回上一页时图像不必要地重新加载

问题描述 投票:0回答:1

我的 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),
      ),
    ],
  );

我尝试过的:

  1. AutomaticKeepAliveClientMixin
    添加到
    NewsTile
    :这并没有解决问题。

  2. 已添加

    CachedNetworkImage

  3. 根据新闻项目的

    Hero
    id
    ,为每个图块使用独特的 
    imageUrl
     标签
    :问题仍然存在。

flutter dart flutter-animation flutter-getx flutter-image
1个回答
0
投票

您似乎遇到了英雄动画的常见行为。 Hero 的工作方式涉及通过三个步骤在小部件树中的不同位置移动小部件:

  1. 原位置(NewsTile 页面)
  2. 过渡期间在叠加层内
  3. 新地点(阅读详情页面)

不幸的是,因此,返回时,英雄动画中涉及的图像不会在原始页面中刷新。发生这种情况是因为小部件被移动到覆盖层,然后又回到原始位置。

在这种情况下,使用 GlobalKey 可以帮助维护小部件状态,但 Hero 与 GlobalKey 不兼容,因此该方法在这里不起作用。

一个可能的解决方案是重构代码,以便在返回时不需要重新加载 initState 或图像。例如,您可以避免重新加载之前缓存的图像,或者研究更高级的状态管理以跨页面保留图像的状态。

© www.soinside.com 2019 - 2024. All rights reserved.