Simple Flutter list view choppy scrolling

5,401

Solution 1

Flutter ListView definitely has an issue in scrolling in debug mode. Although your code will run properly in release mode, without any lag in the scroll. But, still, if you want to scroll without any lag in debug mode, you can prefer SingleChildScrollView over ListView. Just put your scrolling widgets in a Column and put that Column as the child of SingleChildScrollView. In your case, you are using ListView.builder . I will suggest you should use this code to achieve a very smooth scroll:

@override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Flexible(
            child: ListView.builder(
              shrinkWrap: true,
              physics: NeverScrollableScrollPhysics(),
              padding: const EdgeInsets.all(16.0),
              itemCount: litems.length,
              itemBuilder: (BuildContext ctxt, int index) => _buildItem(ctxt, index),
            ),
          )
        ],
      ),
    );
  }

Don't forget to use mainAxisSize: MainAxisSize.min as column size and shrinkWrap: true and physics: NeverScrollableScrollPhysics()

physics: NeverScrollableScrollPhysics() will disable the scroll of your ListView.builder and you will experience an extremely smooth scroll of your list

Solution 2

If you are dealing with static data of very low number of list items, you can speed the list up using addAutomaticKeepAlives: true

Share:
5,401
Abhinav Kaushal Keshari
Author by

Abhinav Kaushal Keshari

Updated on December 07, 2022

Comments

  • Abhinav Kaushal Keshari
    Abhinav Kaushal Keshari over 1 year

    I've been evaluating Flutter for use in an app and started with a very simple example of a list of text. After building this first view, I noticed the list view had choppy scrolling so I looked closer at the showcase apps and it turns out that while Reflectly, for example, is a beautiful app, it suffers from the same problem - very choppy scrolling with a simple list of text. So far I have confirmed this on the iOS simulator, an iPhone XR, Samsung Galaxy Android device and Android Pixel 2 XL simulator.

    I don't see discussions around this so I wonder if I'm doing something wrong but also skeptical I am given how simple my example is and that Reflectly has the same issue.

    What I'd love from the community is to understand: 1. Am I doing anything obviously wrong / stupid to cause this 2. If you run on your device, do you see what I see? 3. Is this known and will be worked on? If I commit to Flutter, can I feel comfortable that my lists will scroll smoothly in the near future?

    Below is the code you can run to reproduce this (sorry it's a bit contrived but I wanted to play around with various Flutter/Dart features):

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            title: 'My List',
            home: Scaffold(
              appBar: AppBar(
                title: Text('My List'),
                backgroundColor: Color.fromRGBO(255, 0, 0, 0.9),
              ),
              body: Padding(
                padding: EdgeInsets.all(16.0),
                child: Column(
                children: [
                  Expanded(child: TimeSelector()),
                ],
              )),
            ));
      }
    }
    
    abstract class ListItem {}
    
    class TimeHeader implements ListItem {
      final String header;
    
      TimeHeader(this.header);
    }
    
    class TimeOption implements ListItem {
      final String timeString;
      final String meridian;
    
      TimeOption(this.timeString, this.meridian);
    }
    
    final List<ListItem> litems = [
      TimeHeader("Morning"),
      TimeOption("10:00", "am"),
      TimeOption("10:30", "am"),
      TimeOption("11:30", "am"),
      TimeHeader("Afternoon"),
      TimeOption("1:00", "pm"),
      TimeOption("1:30", "pm"),
      TimeOption("2:30", "pm"),
      TimeHeader("Night"),
      TimeOption("5:30", "pm"),
      TimeOption("6:30", "pm"),
      TimeOption("7:30", "pm"),
      TimeOption("8:30", "pm"),
      TimeOption("9:30", "pm"),
      TimeOption("10:30", "pm"),
      TimeOption("11:30", "pm"),
      TimeOption("11:45", "pm"),
      TimeOption("11:49", "pm"),
    ];
    
    class TimeSelector extends StatelessWidget {
      final _headerFont = new TextStyle(fontWeight: FontWeight.w600, fontSize: 13.0, color: Color.fromRGBO(164, 164, 164, 1));
      final _smallerFont = const TextStyle(fontSize: 12.0);
    
      @override
      ListView build(BuildContext context) {
        return new ListView.builder(
          padding: const EdgeInsets.all(16.0),
          itemCount: litems.length,
          itemBuilder: (BuildContext ctxt, int index) => _buildItem(ctxt, index),
        );
      }
    
      Widget _buildItem(BuildContext ctxt, int index) {
        final item = litems[index];
    
        if (item is TimeHeader) {
          return new ListTile(
            title: Text(
              item.header,
              style: _headerFont,
            ),
          );
        } else if (item is TimeOption) {
          return new ListTile(
            title: Text(
              item.timeString + item.meridian.toUpperCase(),
              style: _smallerFont,
            ),
          );
        } else {
          return new Text("UNKNOWN");
        }
      }
    }
    
  • Muhammad Tameem Rafay
    Muhammad Tameem Rafay over 2 years
    Althought this solution works good but the drawback of this solution comes out in performance because the whole list renders once. so we can see the lag clearly in app. Simple words it increase the loading time