首页 > 解决方案 > 如何使用带有迭代器的 ListView

问题描述

我想ListView为时间线制作一张“留言卡”。消息数据来自具有多个过滤功能的 Container 类。我在示例中只展示了一个。

编辑:CLARIFICATOIN 我目前有这个 ListView 使用 ListView.builder() 工作,这取决于能够通过索引访问源数据中的元素。

我想更改它,以便元素来自一个迭代,该迭代是在用户滚动列表视图时按需生成的。

在当前的工作解决方案中,提供者有一个 findByChildId,它返回一个列表。该列表通常很长,用户可能只想查看最后 100 条左右的消息。

因此,为了不扫描数千条消息以返回数千条消息,我想象使用 findByChildId 会在用户滚动时产生项目。

class MessageData with ChangeNotifier {
  List<MessageRec> _messages;

  // New Iterable to lazily search only for items the user wants to look at
  Iterable<MessageRec> filterByChildId({String childId}) sync* {
    if (childId == null) {
      throw 'insanity check - Cannot search for null Child ID';
    }
    String previous;
    if (_messages != null) {
      for (MessageRec r in _messages) {
        if (r.properties['thread'] == childId) {
          if (previous == null || ymdFromDt(r.timeSent) != previous) {
            yield DateMark.fromDateString(previous); // Special Message inserted 
            previous = ymdFromDt(r.timeSent);
          }
          yield r;
        }
      }
    }
  }

  // And many other supporting methods here.
}

Note: I assume the above works - this is my first forray into Iterables in Dart / flutter.

The above used to be a method that returned a list of MessageRec by iterating over the entire list and returning all matching items.

The ListView.builder could get items from the resulting list because the elements of a List can be accessed by index.

```dart
   ... Timeline Widget ...
 
   @override
   Widget build(BuildContext context) {
      return Consumer<MessageData>(
         builder: (context, messageData, _) {
            return ListView.builder((context, itemIndex) {
    
               // How to access elements from messageData.filterByChildId(childId) here
               MessageRec nextMessage = messageData.filterByChildId(childId)[itemIndex];
               // The above does not work because there is no indexing on Iterables
               
               return MessageCard.fromMessageRec(nextmessage);
               }
            );
         }
      );
    }
... snip rest of Widget methods

或者答案可能在于使用带有children迭代器形式的普通 ListView,但我认为这仍然会最终创建列表中的所有消息。

标签: flutterasynchronousdartiterator

解决方案


尽管有名称,ListView但并不强制使用List. 您只需将 aList与默认构造函数一起使用,但如果使用ListView.builder,您可以使用 anIterable来生成值。这是一个例子:

@override
Widget build(BuildContext context) =>
  ListView.builder(
    itemBuilder: (BuildContext _, int i) => 
      MessageCard.fromMessageRec(messageData.filterByChildId(childId).elementAt(i)
  );

至于允许的项目数量,文件ListView.builder指出:

此构造函数适用于具有大量(或无限)子级的列表视图,因为仅对那些实际可见的子级调用构建器。块引用


推荐阅读