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

时间:2019-02-20 12:37:39

标签: flutter flutter-layout

我用网络图像创建了一个列表视图,当我尝试滚动列表视图时,滚动并不顺畅,感觉就像在抽动一样。对于缓存,我使用了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),
);
}



}

编辑:将构建配置更改为“发布”后,仍然保持抽动。

4 个答案:

答案 0 :(得分:5)

两件事

  • 考虑使用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.memoryNetworkcached_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(),
      ),
    );
  }
}

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

答案 1 :(得分: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团队必须对其进行优化以提高性能。

另一件事,您的代码无法在稳定的抖动上运行

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.

我必须做一些修改。

答案 2 :(得分:0)

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

df_final = pd.DataFrame({('Year', 'XYZ'): {0: 2001, 1: 2001, 2: 2001, 3: 2001, 4: 2001, 5: 2001}, ('Year', 'ABC'): {0: 2001, 1: 2001, 2: 2001, 3: 2001, 4: 2001, 5: 2001}, ('Quantity', 'XYZ'): {0: 16, 1: 20, 2: 44, 3: 200, 4: 1000, 5: 16}, ('Quantity', 'ABC'): {0: 16, 1: 20, 2: 44, 3: 200, 4: 1000, 5: 16}, ('Car', 'XYZ'): {0: 'Wagonar', 1: 'Zen', 2: np.nan, 3: 'Baleno', 4: 'Swift', 5: 'Wagonar'}, ('Car', 'ABC'): {0: 'Wagonar', 1: np.nan, 2: 'Alto', 3: 'Baleno', 4: 'Swift', 5: np.nan}, ('Colour', 'XYZ'): {0: 'White', 1: 'White', 2: np.nan, 3: 'Silver', 4: 'Red', 5: 'Black'}, ('Colour', 'ABC'): {0: 'White', 1: np.nan, 2: 'Blue', 3: 'Silver', 4: 'Red', 5: np.nan}})

如果您正在仿真器上进行测试,建议您构建发行版APK,将APK安装在Android手机上,然后检查它是否仍然生涩。模拟器占用了资源,因此可能是原因。

最后,您可以尝试减少图像数量,图像类型或尺寸,以查看其是否仍然滞后。

Else在github上报告了此问题,以便颤振团队知道。

答案 3 :(得分:0)

我也研究了一个月,经过大量研究,我发现了一行代码,可以使列表视图或任何列表平滑滚动

只需使用 physics 属性作为 curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT"); 并感受不同

此外,如果您希望将其用于 Column,您可以使用 Singlechildscrollview,并且您可以使用物理属性。