Flutter Web - Scrolling is very laggy for large number of images

3,042

You're not lazily building the pictures. Use ListView.builder instead.

The documentation states in regard to the default ListView constructor:

This constructor is appropriate for list views with a small number of children because constructing the List requires doing work for every child that could possibly be displayed in the list view instead of just those children that are actually visible.

With 50 to 100 2MB images, it would be understandable that your computer is having a hard time.

The documentation states that the ListView.builder constructor builds children on demand.

The ListView.builder constructor takes an IndexedWidgetBuilder, which builds the children on demand. This constructor is appropriate for list views with a large (or infinite) number of children because the builder is called only for those children that are actually visible.

Ex.

ListView.builder(
  itemBuilder: (context, index) {
    if (assets.length > 0) {
      if (assets[index] == null) {
        return null;
      }
      return Container(
        height: 150,
        child: Image.network(assets[index]),
      );
    }
    else {
      if(index > 0) {
        return null;
      }
      return buildZone1(context);
    }
  },
)
Share:
3,042
manish kiranagi
Author by

manish kiranagi

Updated on December 26, 2022

Comments

  • manish kiranagi
    manish kiranagi over 1 year

    I have a Flutter website built on channel beta that is used for uploading large images. When testing on Chrome, scrolling down when there are large number of image rows it is extremely laggy.

    Below is a sample reproduction of the code

    import 'package:flutter/material.dart';
    import 'package:flutter_dropzone/flutter_dropzone.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      DropzoneViewController controller1;
      String message1 = 'Drop something here';
      bool highlighted1 = false;
      List assets = [];
      @override
      Widget build(BuildContext context) => MaterialApp(
            home: Scaffold(
              appBar: AppBar(
                title: const Text('Dropzone example'),
              ),
              body: ListView(
                children: [
                  if (assets.length > 0)
                    _showAssets(assets)
                  else
                    buildZone1(context),
                  Padding(
                    padding: const EdgeInsets.all(30),
                    child: Container(
                      width: 100,
                      child: MaterialButton(
                        color: Colors.greenAccent,
                        child: Text('Browse files'),
                        onPressed: () =>
                            controller1.pickFiles(multiple: true).then((files) {
                          files.forEach((file) {
                            controller1.createFileUrl(file).then((url) {
                              setState(() {
                                print('in set state');
                                assets.add(url);
                              });
                            });
                          });
                        }),
                      ),
                    ),
                  ),
                  Container(height: 400, color: Colors.lightGreen),
                  Container(height: 400, color: Colors.redAccent),
                ],
              ),
            ),
          );
      Widget _showAssets(List assets) {
        //print(assets);
        return Wrap(
          children: assets.map((asset) {
            return Container(
              height: 150,
              child: Image.network(asset),
            );
          }).toList(),
        );
      }
    
      Widget buildZone1(BuildContext context) => Builder(
            builder: (context) => Container(
              height: 200,
              child: DropzoneView(
                operation: DragOperation.copy,
                cursor: CursorType.grab,
                onCreated: (ctrl) => controller1 = ctrl,
                onLoaded: () => print('Zone 1 loaded'),
                onError: (ev) => print('Zone 1 error: $ev'),
                onHover: () {
                  setState(() => highlighted1 = true);
                  //print('Zone 1 hovered');
                },
                onLeave: () {
                  setState(() => highlighted1 = false);
                  //print('Zone 1 left');
                },
                onDrop: (ev) {
                  print('Zone 1 drop: ${ev.name}');
                  setState(() {
                    print('in set state');
                    message1 = '${ev.name} dropped';
                    highlighted1 = false;
                  });
                },
              ),
            ),
          );
    }
    
    

    pubspec.yaml

    name: file_upload
    description: A new Flutter project.
    
    
    publish_to: 'none' 
    
    https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
    version: 1.0.0+1
    
    environment:
      sdk: ">=2.7.0 <3.0.0"
    
    dependencies:
      flutter:
        sdk: flutter
      flutter_dropzone: ^1.0.9
    
    
      # The following adds the Cupertino Icons font to your application.
      # Use with the CupertinoIcons class for iOS style icons.
      cupertino_icons: ^1.0.1
    
    dev_dependencies:
      flutter_test:
        sdk: flutter
    
    # For information on the generic Dart part of this file, see the
    # following page: https://dart.dev/tools/pub/pubspec
    
    # The following section is specific to Flutter.
    flutter:
    
      # The following line ensures that the Material Icons font is
      # included with your application, so that you can use the icons in
      # the material Icons class.
      uses-material-design: true
    

    To reproduce

    • Click on Browse files and select over 50 to 100 images of over 2MB to display over 10 rows
    • Try to scroll down when the images are visible
  • manish kiranagi
    manish kiranagi over 3 years
    Spot on! The lazy building of the List indeed helps the scrolling. My production code uses GridView.builder and I am also using cacheExtent to make the scrolling experience smoother. Many thanks!. Sorry for the late up tick.