Flutter Web - 对于大量图像,滚动非常滞后

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

我有一个建立在频道测试版上的 Flutter 网站,用于上传大图片。 在 Chrome 上测试时,当有大量图像行时向下滚动会非常卡顿。

下面是代码的示例复制

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

重现

您没有懒惰地构建图片。请改用 ListView.builder

关于默认 ListView 构造函数的文档说明:

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.

有 50 到 100 张 2MB 图片,您的计算机遇到困难是可以理解的。

文档指出 ListView.builder 构造函数按需构建子项。

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.

例如

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);
    }
  },
)

我遇到了同样的问题,我通过在保持保真度的同时将图像压缩和缩小到尽可能低的形式来解决它。压缩图像在滚动时特别显示出延迟方面的重大改进