Flutter中如何保存每个列表对象的状态

Posted

技术标签:

【中文标题】Flutter中如何保存每个列表对象的状态【英文标题】:How to preserve the state of each list object in Flutter 【发布时间】:2020-03-31 06:50:02 【问题描述】:

我有一个网络套接字,它发送带有一些数据的图像,然后我将它们显示在 AnimatedList 中。问题是每个新数据都进来了,它会重新加载列表中的每一个项目,列表会重新加载每个图像。也因为图片是base64转换的,所以不能兑现。

有什么方法可以保留AnimatedList 中每个对象的状态,以便在添加新项目时不会重新加载列表中的所有其他对象/图像。

AnimatedList 样本:

AnimatedList(
  key: node.validListKey,
  controller: widget.scrollController,
  padding: EdgeInsets.fromLTRB(10, 10, 0, 10),
  initialItemCount: node.data.length,
  itemBuilder: (context, index, animation) 
    return FadeTransition(
      opacity: CurvedAnimation(
          parent: animation,
          curve: Interval(0, 0.2, curve: Curves.ease)),
      child: SizeTransition(
        sizeFactor:
            CurvedAnimation(parent: animation, curve: Curves.ease),
        child: DataContainer(data[index])
      ),
    );
  ,
),

基本解码示例:

child: AspectRatio(
  aspectRatio: 1 / 1,
  child: ExtendedImage.memory(
    base64.decode(data.base),
    fit: BoxFit.cover,
    loadStateChanged: (state) 
      if (state.extendedImageLoadState ==
          LoadState.completed) 
        return ExtendedRawImage(
          image: state.extendedImageInfo?.image,
        );
      
      return Center(child: CircularProgressIndicator());
    ,
  ),
),

更新#1 似乎问题在于我如何在列表中插入项目。因为我在列表的开头插入了新项目,由于某种原因,它只为最后一个元素调用 init 状态,而不是最近添加的元素。当我在列表末尾插入时,问题就解决了。有什么办法可以强制为最近添加的项目而不是最后一个项目调用初始化状态?

插入项目示例:

array.add(data);
array.insert(0, data);
if (key.currentState != null)
  key.currentState.insertItem(0, duration: _insertDuation);

更新#2 因此,我能够通过将 AnimatedList 包裹在 SingleChildScrollView 中,添加 reverse: trueshrinkWrap: true 并在 initState 方法中添加 decode 来解决我的图像重新加载的第一个问题。

SingleChildScrollView(
  child : ListView.builer(
    shrinkWrap: true,
    reverse: true,
    physics: NeverScrollableScrollPhysics(),
    itemBuilder: (BuildContext context, int index) 
      ...
    ,
  )
);

但现在问题出在remove 方法上。当我尝试从列表中删除项目时,基本小部件内容保持不变,但图像会更改一个索引。我已经尝试为每个小部件添加唯一键,但是在添加数据时会强制重新加载每个图像。

_data.removeAt(0);
if (_validListKey.currentState != null)
  _validListKey.currentState.removeItem(
      0, (context, animation) => Container(),
      duration: Duration.zero);

【问题讨论】:

很可能是您的node.validListKey 发生了变化。 AnimatedList 不会破坏列表项的状态 @RémiRousselet 我使用Provider 包来管理AnimatedList (final NodeHelper node = Provider.of<NodeHelper>(context, listen: false);) 的状态和密钥。这会是个问题吗? 【参考方案1】:

您应该在 initState 函数(或在 initState 中触发的异步函数)中执行 base64.decode(data.base) 并缓存结果。

您的构建函数不应触发此解码,或者不应运行任何具有副作用的代码。现在,在每次构建时,您都在进行解码并为ExtendedImage 提供不同的Uint8List 实例。如果ExtendedImage 被正确实现,当它在新的build() 调用中被赋予相同的引用时,它不应该做任何UI 更改。

【讨论】:

问题是在initState 中我一直只得到第一个值,直到它离开屏幕。因此,所有图像都是相同的。也许问题出在 Keys... 之类的其他东西上

以上是关于Flutter中如何保存每个列表对象的状态的主要内容,如果未能解决你的问题,请参考以下文章

如何在浏览器本地存储 Flutter Web 应用程序中保存对象列表

使用 Provider 将 Map 的状态保存到 Flutter 应用

颤动 - 如何在颤动中保存状态选择的单选按钮列表?

如何删除ngrx中以前的存储状态?

flutter 保持页面状态

在 Flutter 中使用 ListView 从 API 检索 json 对象列表时。拥有有状态或无状态小部件是不是正确?