如何在Flutter中实现ListView平滑滚动

问题描述 投票:3回答:3

我已经创建了一个带有网络图像的列表视图,当我试图滚动列表视图时,它的滚动并不顺畅,感觉就像抽搐一样。对于缓存,我使用了cached_network_image:any,这个库本身工作正常,但listview没有滚动顺利。

我知道我们可以使用Future小部件实现这一点,但不知道如何在将来返回缓存的图像。

import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';

void main() {
   runApp(
      MaterialApp(
        title: 'List view with network images',
        home: ListViewController(),

     )
  );
}


class ListViewController extends StatelessWidget {

var imagesArray = [
  "http://iastro.shangcarts.com/pub/media/notice/File-1550484786.jpeg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1550218043.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1550217808.jpeg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1550111913.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1550108862.jpeg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1550024618.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1550022739.jpeg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1549935759.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1549935073.jpeg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1549850545.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1549849978.jpeg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1549008412.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1548985261.jpeg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1548821873.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1548731040.jpeg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1548641672.jpeg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1548410089.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547774905.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547701178.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547625318.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547624883.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547619153.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547606341.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547606200.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547603338.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547602464.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547454842.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547192524.jpg",
  "http://iastro.shangcarts.com/pub/media/notice/File-1547191374.jpg"
];




Widget _imageCell(String imageUrl) {

return ListTile(
  leading: CachedNetworkImage(imageUrl: imageUrl, placeholder: CircularProgressIndicator(), errorWidget: Icon(Icons.error),),
);

}


@override
Widget build(BuildContext context) {
// TODO: implement build
return Material(
  child: ListView.separated(
      itemBuilder: (BuildContext context, int index) {
        return _imageCell(imagesArray[index]);
      },
      separatorBuilder: (context, index) => Divider(
        color: Colors.black,
      ),
      itemCount: imagesArray.length),
);
}



}

编辑:将构建配置更改为Release仍然相同,抽搐。

flutter flutter-layout
3个回答
5
投票

2件事

  • 考虑使用FadeInImage.memoryNetwork而不是cached_network_image,和/或
  • 考虑使用ListView(children: List<Widget> )而不是ListView.separated(itemBuilder: )

FadeInImage.memoryNetwork

参考https://flutter.dev/docs/cookbook/images/fading-in-images

在运行示例代码时,我不禁注意到cached_network_image做了一些影响主UI线程的图像重新缩放/采样,很可能这个包在主线程上执行计算量很大的任务。使用官方烹饪书为我(Android模拟器),完整的示例代码(您可能想要将kTransparentImage更改为其他一些加载图标)产生更好的结果

import 'package:flutter/material.dart';
import 'package:transparent_image/transparent_image.dart';

void main() {
  runApp(MaterialApp(
    title: 'List view with network images',
    home: ListViewController(),
  ));
}

class ListViewController extends StatelessWidget {
  var imagesArray = [
    "http://iastro.shangcarts.com/pub/media/notice/File-1550484786.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550218043.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550217808.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550111913.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550108862.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550024618.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550022739.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1549935759.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1549935073.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1549850545.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1549849978.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1549008412.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1548985261.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1548821873.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1548731040.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1548641672.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1548410089.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547774905.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547701178.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547625318.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547624883.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547619153.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547606341.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547606200.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547603338.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547602464.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547454842.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547192524.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547191374.jpg"
  ];

  Widget _imageCell(String imageUrl) {
    return ListTile(
        leading: FadeInImage.memoryNetwork(
      placeholder: kTransparentImage,
      image: imageUrl,
    ));
  }

  @override
  Widget build(BuildContext context) {
// TODO: implement build
    return Material(
      child: 
      ListView.separated(
          itemBuilder: (BuildContext context, int index) {
            return _imageCell(imagesArray[index]);
          },
          separatorBuilder: (context, index) => Divider(
                color: Colors.black,
              ),
          itemCount: imagesArray.length),
    );
  }
}

ListView(children: List<Widget> )

参考https://docs.flutter.io/flutter/widgets/ListView-class.html

其次,如果你事先知道你将有这个有限的不那么长的列表,也许你想使用ListView(children: List<Widget> )而不是ListView.separated(itemBuilder: ),因为itemBuilder将更频繁地调用/调用函数,并且现在图像被缓存(无论是FadeInImage.memoryNetwork还是cached_network_image)仅限完整内容,不是缩略图,@ user1462442提及源图像大小,我同意该评估。我们可以做的是将调用减少到尽可能低的数字。

例如:

import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';

void main() {
  runApp(MaterialApp(
    title: 'List view with network images',
    home: ListViewController(),
  ));
}

class ListViewController extends StatelessWidget {
  var imagesArray = [
    "http://iastro.shangcarts.com/pub/media/notice/File-1550484786.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550218043.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550217808.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550111913.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550108862.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550024618.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1550022739.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1549935759.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1549935073.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1549850545.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1549849978.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1549008412.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1548985261.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1548821873.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1548731040.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1548641672.jpeg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1548410089.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547774905.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547701178.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547625318.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547624883.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547619153.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547606341.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547606200.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547603338.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547602464.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547454842.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547192524.jpg",
    "http://iastro.shangcarts.com/pub/media/notice/File-1547191374.jpg"
  ];

  Widget _imageCell(String imageUrl) {
    return ListTile(
      leading: CachedNetworkImage(
        imageUrl: imageUrl,
        placeholder: CircularProgressIndicator(),
        errorWidget: Icon(Icons.error),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
// TODO: implement build
    return Material(
      child: ListView(
        children: imagesArray.map((imageUrl) => _imageCell(imageUrl)).toList(),
      ),
    );
  }
}

如上所述,您也可以同时应用这两个建议。


0
投票

除了减少源图像大小之外,我认为现在还没有一个好的解决方案。我看了一下你的图像列表,有些图像非常庞大。

https://github.com/renefloor/flutter_cached_network_image/issues/90

https://github.com/pejalo/flutter_image_performance

https://github.com/flutter/flutter/issues/25469

https://github.com/flutter/flutter/issues/27625#issuecomment-461677587

https://github.com/flutter/flutter/issues/2848

https://github.com/flutter/flutter/issues/26194

颤动降尺度很慢。颤振团队必须优化它以提高性能。

另一件事,你的代码不会在flutter stable上运行

Flutter 1.0.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 5391447fae (3 months ago) • 2018-11-29 19:41:26 -0800
Engine • revision 7375a0f414
Tools • Dart 2.1.0 (build 2.1.0-dev.9.4 f9ebf21297)

Compiler message:
lib/main.dart:56:64: Error: The argument type '#lib1::CircularProgressIndicator'
can't be assigned to the parameter type '(#lib2::BuildContext, dart.core::String)
→ #lib2::Widget'.
Try changing the type of the parameter, or casting the argument to
'(#lib2::BuildContext, dart.core::String) → #lib2::Widget'.
  leading: CachedNetworkImage(imageUrl: imageUrl, placeholder:
  CircularProgressIndicator(), errorWidget: Icon(Icons.error),),
                                                               ^
lib/main.dart:56:106: Error: The argument type '#lib1::Icon' can't be assigned to
the parameter type '(#lib2::BuildContext, dart.core::String, dart.core::Exception)
→ #lib2::Widget'.
Try changing the type of the parameter, or casting the argument to
'(#lib2::BuildContext, dart.core::String, dart.core::Exception) → #lib2::Widget'.
  leading: CachedNetworkImage(imageUrl: imageUrl, placeholder:
  CircularProgressIndicator(), errorWidget: Icon(Icons.error),),
                                                                                                         ^
Compiler failed on /Users/blah/stackoverflow/issue_54786567/lib/main.dart
Error launching application on iPhone XR.


flutter run
Launching lib/main.dart on iPhone XR in debug mode...
Starting Xcode build...                                          
 ├─Assembling Flutter resources...                    3.9s

 └─Compiling, linking and signing...                  3.4s

Xcode build done.                                            9.1s
 5.8s
Syncing files to device iPhone XR...                             
flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following assertion was thrown during performLayout():
flutter: BoxConstraints forces an infinite height.
flutter: These invalid constraints were provided to RenderSemanticsAnnotations's layout() function by the
flutter: following function, which probably computed the invalid constraints in question:
flutter:   RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:258:13)
flutter: The offending constraints were:
flutter:   BoxConstraints(w=382.0, h=Infinity)
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0      BoxConstraints.debugAssertIsValid.<anonymous closure>.throwError (package:flutter/src/rendering/box.dart:504:9)
flutter: #1      BoxConstraints.debugAssertIsValid.<anonymous closure> (package:flutter/src/rendering/box.dart:547:21)
flutter: #2      BoxConstraints.debugAssertIsValid (package:flutter/src/rendering/box.dart:551:6)
flutter: #3      RenderObject.layout (package:flutter/src/rendering/object.dart:1549:24)
flutter: #4      RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:258:13)
flutter: #5      RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #6      _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:104:13)
flutter: #7      RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #8      RenderStack.performLayout (package:flutter/src/rendering/stack.dart:510:15)
flutter: #9      RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #10     _RenderListTile._layoutBox (package:flutter/src/material/list_tile.dart:892:9)
flutter: #11     _RenderListTile.performLayout (package:flutter/src/material/list_tile.dart:913:30)
flutter: #12     RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #13     RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:199:11)
flutter: #14     RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #15     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:104:13)
flutter: #16     RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #17     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:104:13)
flutter: #18     RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #19     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:104:13)
flutter: #20     RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #21     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:104:13)
flutter: #22     RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #23     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:104:13)
flutter: #24     RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #25     RenderSliverList.performLayout (package:flutter/src/rendering/sliver_list.dart:164:27)
flutter: #26     RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #27     RenderSliverPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:182:11)
flutter: #28     RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
flutter: #29     RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:405:13)
flutter: #30     RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1316:12)
flutter: #31     RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1234:20)
flutter: #32     RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:1509:7)
flutter: #33     PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:768:18)
flutter: #34     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:281:19)
flutter: #35     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:677:13)
flutter: #36     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:219:5)
flutter: #37     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:990:15)
flutter: #38     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:930:9)
flutter: #39     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:842:5)
flutter: #40     _invoke (dart:ui/hooks.dart:154:13)
flutter: #41     _drawFrame (dart:ui/hooks.dart:143:3)
flutter:
flutter: The following RenderObject was being processed when the exception was fired:
flutter:   RenderConstrainedBox#57507 relayoutBoundary=up12 NEEDS-LAYOUT NEEDS-PAINT
flutter:   creator: ConstrainedBox ← Container ← FadeTransition ← Stack ← StreamBuilder<FileInfo>-[#fb1e3] ←
flutter:   CachedNetworkImage ← IconTheme ← Builder ← _ListTile ← MediaQuery ← Padding ← SafeArea ← ⋯
flutter:   parentData: <none> (can use size)
flutter:   constraints: BoxConstraints(0.0<=w<=382.0, 0.0<=h<=Infinity)
flutter:   size: MISSING
flutter:   additionalConstraints: BoxConstraints(biggest)
flutter: This RenderObject had the following descendants (showing up to depth 5):
flutter:   RenderSemanticsAnnotations#494da NEEDS-LAYOUT NEEDS-PAINT
flutter:     RenderImage#98201 NEEDS-LAYOUT NEEDS-PAINT
flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════
flutter: Another exception was thrown: RenderBox was not laid out: RenderConstrainedBox#57507 relayoutBoundary=up12 NEEDS-PAINT
flutter: Another exception was thrown: BoxConstraints forces an infinite height.
flutter: Another exception was thrown: RenderBox was not laid out: RenderConstrainedBox#ac73c relayoutBoundary=up12 NEEDS-PAINT
flutter: Another exception was thrown: BoxConstraints forces an infinite height.
flutter: Another exception was thrown: RenderBox was not laid out: RenderConstrainedBox#95164 relayoutBoundary=up12 NEEDS-PAINT
flutter: Another exception was thrown: BoxConstraints forces an infinite height.
flutter: Another exception was thrown: RenderBox was not laid out: RenderConstrainedBox#9efb3 relayoutBoundary=up12 NEEDS-PAINT
flutter: Another exception was thrown: BoxConstraints forces an infinite height.
flutter: Another exception was thrown: RenderBox was not laid out: RenderConstrainedBox#16fcc relayoutBoundary=up12 NEEDS-PAINT
flutter: Another exception was thrown: BoxConstraints forces an infinite height.

我必须做一些修改。


0
投票

尝试将此添加到您的列表视图:

 physics: const AlwaysScrollableScrollPhysics(),

如果您在模拟器上进行测试,我建议您构建发布APK,在您的Android手机上安装APK并检查它是否仍然生涩。模拟器是资源占用,所以它可能是一个原因。

最后,您可以尝试减少图像数量,图像类型或大小,以查看它是否仍然是滞后的。

另外在github上报告这个问题,以便颤振团队知道。

© www.soinside.com 2019 - 2024. All rights reserved.