【问题标题】:Flutter ListView.builder() dynamic list - shows inifinitely repeating entriesFlutter ListView.builder() 动态列表 - 显示无限重复的条目
【发布时间】:2019-02-14 03:29:07
【问题描述】:

我有一个大约 5K 的大型项目列表。

我想做的是为这些项目编写一个搜索视图。

我尝试了以下 -

   List<String> items;
   String query;

   ListView.builder(
    itemBuilder: (context, index) {
      for (int i = index; i < items.length; i++) {
        var item = items[i];
        if (item.contains(query)) {
          return ItemTile(item);
        }
      }
    }

这可以有效地渲染和搜索元素,但问题是它最终会无限重复列表中的最后一项。

我猜那是因为我没有提供itemCount


所以我尝试自己在 Stateful 小部件中跟踪过滤项目的数量。

   var _count = 1;

   _queryController.addListener(() {
      setState(() => _count = 1);
   });

   ListView.builder(
    itemBuilder: (context, index) {
      for (int i = index; i < items.length; i++) {
        var item = items[i];
        if (item.contains(query)) {
          setState(() => _count += 1);
          return ItemTile(item);
        }
     }
     itemCount: _count;
   }

然后我收到一个错误,说 - setState() or markNeedsBuild() called during build.

在不为每个查询完全搜索项目的情况下,正确的方法是什么?

(我的目标是在输入时搜索 UX)

【问题讨论】:

    标签: listview dart flutter


    【解决方案1】:

    您可以尝试在将列表传递给构建器之前对其进行过滤。

    List<String> items;
    List<String> _queryResults;
    String query;
    
    _queryResults = items.where((item) => item.contains(query)).toList();
    

    然后可以将其传递给 ListView.builder 而不必一遍又一遍地设置状态。不确定与其他选项相比它的性能如何,应该不会有太大差异,因为在大多数情况下,过滤后的列表可能会很短。这比在构建器中进行过滤和设置状态要干净得多,所以我至少会测试一下。

    此外,如果您要使用边输入边搜索的解决方案,还应该取消过滤,这意味着您在每次输入后等待 500 毫秒或一段合适的持续时间,以查看用户是否输入更多内容,然后再进行过滤.将为您节省大量不必要的电话,并使您的解决方案性能更好。

    【讨论】:

    • 谢谢,这似乎很好用。 250ms 的去抖动让它变得更好!
    【解决方案2】:

    这是一种添加去抖动的可能方法:-

    var _controller = TextEditingController();
    List<dynamic> _filtered;
    
    @override
    void initState() {
      _filtered = widget.items;
    
      _controller.addListener(() {
        var query = _controller.text;
        Future.delayed(Duration(milliseconds: 250), () {
          if (!mounted) {
            return;
          }
          if (_controller.text == query) {
            setState(() {
              _filtered = widget.items
                  .where((item) => item.contains(query)).toList())
                  .toList();
            });
          }
        });
      });
    
      super.initState();
    }
    
    ...
    
    ListView.builder(
      itemBuilder: (context, index) => ItemTile(_filtered[index]),
      itemCount: _filtered.length,
    )
    

    【讨论】:

      【解决方案3】:

      您在 Listview.builder 中使用 for 循环,这不是必需的。 ListView.builder 将自动循环到列表中的项目数...

      试试这个。

      List<String> items;
      String query;
      
      ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        var item = items[index];
        if (item.contains(query)) {
            setState(() => _count += 1);
            return ItemTile(item);
        }
      }
      

      【讨论】:

      • 这种方法不会导致与查询不匹配的列表项的代码路径更长吗?
      • 没关系。这并不能解决我原来的问题。
      猜你喜欢
      • 1970-01-01
      • 2019-01-31
      • 2019-07-04
      • 2020-05-19
      • 2017-09-17
      • 2021-06-13
      • 1970-01-01
      • 2019-08-19
      • 2018-10-29
      相关资源
      最近更新 更多