Flutter: scrolling a list of DropdownButtons each containing 1k selections is too slow

1,572

ListView will create and destroy widgets as they come in and out of view. Your MyItem widget is a very heavy widget (lots of stuff to create and destroy).

You probably don't want each MyItem to be a Scaffold(). Normally you only have 1 Scaffold() visible as it's a fancy root view for an app. It has an app bar, snack bar, drawer, etc. Try having just your Container(...) that's currently under body: as the return from your MyItem.build().

In the items: of your DropdownButton, you build and destroy the list of items when the DropdownButton scrolls in and out of view. If this list is the same for every widget in your list like in your test code above, create one List<Widget>[] that contains your DropdownMenuItem widgets and pass it in to your MyItem() widgets. Something like:

//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 - we have a ListView with complex children that we test with 10,000 items. There's a significant difference in performance between the debug and release builds in Flutter. It stutters a little in the debug builds but is very smooth in the release builds.

Share:
1,572
Mena
Author by

Mena

⦿Part of the Top 10% Android answers on Stackoverflow. ⦿Part of the Top 5% Retrofit answers on Stackoverflow. ⦿Top 8% Overall Stackoverflow Answers for the year 2021. ⦿Top 9% Overall Stackoverflow Answers for the year 2020. ⦿Top 8% Overall Stackoverflow Answers for the year 2019.

Updated on December 02, 2022

Comments

  • Mena
    Mena over 1 year

    I have a list of items (5-6 items) that are displayed using a ListView.builder. Each item contains a DropdownButton widget for the user to pick a number from 1 - 1000, thus containing 1000 DropdownMenuItems.

    I implemented it as shown below, but the problem is that scrolling down the ListView is too slow and stutters. Even if the listView has 5 or 6 items, but note that each of them has an embedded DropdownButton containing 1000 DropdownMenuItems.

    Is there a fix? Or another way to achieve my requirement?

    N.B: Even if I reduce the number of DropdownMenuItems to 100, it still stutters when scrolling down the 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(),
            ),
          ),
        );
      }
    

    Edit

    I changed MyItem class to be as below, but still, the same problem exists.

    Tried using ListView and ListView.custom instead of ListView.builder, to build the whole list in advance instead of lazily according to this, but still same issue.

    I also tried running the app using --profile configuration to simulate a release version. The performance is better but still suffers from terrible stuttering and lag. Tested on emulator and physical device.

     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, 
                ),
              ),
            );
          }
    
    • Pat9RB
      Pat9RB over 2 years
      What happens if you replace DropdownButton() with a SizedBox() of the same width/height? What happens if you replace DropdownButton() with a Column(children: quantityList)? Do either of these exhibit the same performance issues?
    • Mena
      Mena over 2 years
      @Pat9RB No, if I use a very long column of 1000 Text Widgets there is no problem.