Search code examples
flutterflutter-web

Flutter columns scrolling gets very laggy with higher row counts


so I am trying to build a multi platform table for my flutter project. But when the row count gets larger than a few hundred, the scrolling geht's extremely laggy, especially in a web application. The build process also takes almost 5 seconds. To build the tab I use a Column with identical build Rows inside a SingleChildScrollView. The Table class of Flutter has the same issue and I couldn't find a working package on pub.dev jet.

Even in a Project where only this Table exists, the scrolling is not acceptable. What can I do to build a large row count like 1000 or more with a smooth scrolling?

Here is the simplified code:

import 'package:flutter/material.dart';

class MyTable extends StatefulWidget{
  @override
  State<MyTable> createState() => _MyTableState();
}

class _MyTableState extends State<MyTable> {

  final double columnSpace = 5;
  final double rowSpace = 5;

  final decoration = BoxDecoration(
    borderRadius: BorderRadius.circular(5),
    color: Colors.grey,
  );

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        children: List.generate(1000, (index) => _buildRow(index)),
      ),
    );
  }

  _buildRow(int index){
    return Column(
      children: [
        SizedBox(
          height: 40,
          child: Row(
            children: [
              _buildExpandedCell(10, index.toString()),
              SizedBox(width: rowSpace,),
              _buildExpandedCell(4, index.toString()),
              SizedBox(width: rowSpace,),
              _buildExpandedCell(3, index.toString()),
              SizedBox(width: rowSpace,),
              _buildExpandedCell(3, index.toString()),
              SizedBox(width: rowSpace,),
              _buildExpandedCell(3, index.toString()),
              SizedBox(width: rowSpace,),
              Container(
                decoration: decoration,
                width: 90,
              ),
            ],
          ),
        ),
        SizedBox(height: columnSpace,),
      ],
    );
  }
  _buildExpandedCell(int flex, String content){
    return Expanded(
        flex: flex,
        child: Container(
          height: double.infinity,
          decoration: decoration,
          child: Center(child: Text(content)),
        ),
      );
  }
}

Solution

  • You should use a ListView.builder instread of a Column

    For your example that would be instead of

    @override
    Widget build(BuildContext context) {
      return SingleChildScrollView(
        child: Column(
          children: List.generate(1000, (index) => _buildRow(index)),
        ),
      );
    }
    

    do

    @override
    Widget build(BuildContext context) {
      return ListView.builder(
        itemCount: 1000,
        itemBuilder: (context, index) => _buildRow(index),
      );
    }
    

    The reason is that Columns load all children in memory, even the non-visible ones. With a ListView.builder it only loads the ones that are visible on screen.