【问题标题】:Flutter: scrolling a list of DropdownButtons each containing 1k selections is too slowFlutter:滚动每个包含 1k 个选择的 DropdownButtons 列表太慢
【发布时间】:2021-11-13 11:52:15
【问题描述】:

我有一个使用 ListView.builder 显示的项目列表(5-6 项)每个项目包含一个 DropdownButton 小部件,供用户从 1 到 1000 中选择一个数字,因此包含 1000 个 DropdownMenuItems

我实现如下图,但问题是向下滚动ListView太慢而且卡顿。即使 listView 有 5 或 6 个项目,但请注意,每个项目都有一个嵌入的 DropdownButton,其中包含 1000 个 DropdownMenuItem。

有解决办法吗?或者其他方式来满足我的要求?

注意:即使我将 DropdownMenuItem 的数量减少到 100 个,它仍然会在向下滚动 ListView 时卡顿

class List extends StatelessWidget {
   final List<Item> // Contains 5 items.
   final List<int> quantityList = List<int>.generate(1000, (int i) => i);
 //--
   child: ListView.builder(
                  itemBuilder: (buildContext, i) {
                    return MyItem(
                      quantityList,
                    );
                  },
                  itemCount: items.length(),
                )

class MyItem extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        child: DropdownButton<int>(
          items: quantityList
              .map(
                (int e) =>
                DropdownMenuItem<int>(
                  value: e,
                  child: Text(e.toString()),
                ),
          )
              .toList(),
        ),
      ),
    );
  }

编辑

我将 MyItem 类更改为如下,但仍然存在同样的问题。

尝试使用 ListViewListView.custom 而不是 ListView.builder,根据this提前而不是懒惰地构建整个列表,但仍然是同样的问题。

我还尝试使用--profile 配置运行应用程序来模拟发布版本。性能更好,但仍然遭受可怕的口吃和滞后。在模拟器和物理设备上测试。

 class MyItem extends StatelessWidget {
      List<DropDownMenuItem> quantityList; // contains 1k 
      @override
      Widget build(BuildContext context) {
        return Container(
            width:300,
            height:300,
            child: DropdownButton<int>(
              items: quantityList, 
            ),
          ),
        );
      }

【问题讨论】:

  • 如果将 DropdownButton() 替换为相同宽度/高度的 SizedBox() 会发生什么?如果将 DropdownButton() 替换为 Column(children: quantityList) 会发生什么?这些中的任何一个都表现出相同的性能问题吗?
  • @Pat9RB 不,如果我使用包含 1000 个文本小部件的非常长的列,则没有问题。

标签: flutter flutter-listview flutter-dropdownbutton


【解决方案1】:

ListView 将在小部件进出视图时创建和销毁它们。您的 MyItem 小部件是一个非常重的小部件(需要创建和销毁很多东西)。

您可能不希望每个MyItem 都成为Scaffold()。通常,您只有 1 个 Scaffold() 可见,因为它是应用程序的精美根视图。它有一个应用栏、小吃店、抽屉等。尝试只使用当前位于body: 下的Container(...) 作为MyItem.build() 的返回。

在 DropdownButton 的 items: 中,您可以在 DropdownButton 滚动进出视图时构建和销毁项目列表。如果此列表对于列表中的每个小部件(如上面的测试代码)都相同,请创建一个包含 DropdownMenuItem 小部件的 List&lt;Widget&gt;[] 并将其传递给您的 MyItem() 小部件。比如:

//In your widget with the ListView
List<Widget> myItems;

//In the initState() of your widget with the ListView
...
myItems = quantitySelection.map(
   (int e) => DropdownMenuItem<int>(
      value: e,
      child: Text(e.toString()),
    ),
).toList(),
...


//In your ListView.builder()
return MyItem(
  ...  
  items: myItems,
  ...
);

//In your MyItem.build() ->  DropdownButton()
...
DropDownButton(
   items: items
),
...

FWIW - 我们有一个包含复杂子项的 ListView,我们用 10,000 个项目进行测试。 Flutter 中的调试版本和发布版本之间的性能存在显着差异。它在调试版本中有点卡顿,但在发布版本中非常流畅。

【讨论】:

    【解决方案2】:

    我能够通过仅使用ListView.buildercacheExtent 属性将其设置为list.length*200 来解决此问题。这是一种解决方法,因为知道在我的情况下列表长度总是很小。

    预先构建 DropDownMenuItems 并没有让用户感觉到性能提升,但无论如何这是一个很好的推荐做法,因为不要为每个列表项一遍又一遍地构建相同的 DropDownMenuItems。

    虽然根据docs: ListView 和 ListView.separated 并没有延迟加载项目,而是在开始时将它们全部构建起来,但我在滚动过程中一直遇到与 ListView.builder 相同的卡顿和延迟。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-16
      • 1970-01-01
      • 2016-03-07
      • 1970-01-01
      • 2021-01-02
      相关资源
      最近更新 更多