如何在Flutter中实现ListView平滑滚动
How to achieve ListView smooth scrolling in Flutter
我创建了一个包含网络图像的列表视图,当我尝试滚动列表视图时,它的滚动并不平滑,感觉像是在抽搐。对于缓存,我使用了 cached_network_image: any,这个库本身工作正常,但列表视图滚动不平滑。
我知道我们可以使用 Future 小部件实现此目的,但不知道如何 return 使用 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 后仍然相同,抽搐。
除了减小源图像的大小,我认为目前没有好的解决方案。我看了你的图片列表,有些图片很大。
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 团队必须对其进行性能优化。
另一件事,你的代码没有 运行 on 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/Whosebug/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.
我必须做一些修改。
尝试将此添加到您的列表视图:
physics: const AlwaysScrollableScrollPhysics(),
如果您在模拟器上进行测试,我建议构建发布 APK,将 APK 安装到您的 Android phone 上,然后检查它是否仍然不稳定。模拟器占用资源,所以这可能是一个原因。
最后,您可以尝试减少图片数量、图片类型或尺寸,看看是否仍然卡顿。
否则请在 github 报告此问题,以便 flutter 团队了解。
2 件事
- 考虑使用
FadeInImage.memoryNetwork
而不是 cached_network_image
、and/or
- 考虑使用
ListView(children: List<Widget> )
而不是 ListView.separated(itemBuilder: )
FadeInImage.memoryNetwork
参考 https://flutter.dev/docs/cookbook/images/fading-in-images
当 运行 你的示例代码时,我不禁注意到 cached_network_image
做了一些图像 rescaling/sampling 影响主 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
将 invoke/call 更频繁地使用这些功能,并且现在仅针对完整内容缓存图像(通过 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(),
),
);
}
}
如上所述,您也可以应用这两个建议。
我也看了一个月,经过大量研究,我发现了一行代码,使列表视图或任何列表都非常平滑滚动
只需使用 物理 属性 作为 physics: BouncingScrollPhysics(),
并感受差异
另外,如果你想将它用于 Column,你可以使用 Singlechildscrollview 并且在其中,你可以使用物理 属性.
我创建了一个包含网络图像的列表视图,当我尝试滚动列表视图时,它的滚动并不平滑,感觉像是在抽搐。对于缓存,我使用了 cached_network_image: any,这个库本身工作正常,但列表视图滚动不平滑。
我知道我们可以使用 Future 小部件实现此目的,但不知道如何 return 使用 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 后仍然相同,抽搐。
除了减小源图像的大小,我认为目前没有好的解决方案。我看了你的图片列表,有些图片很大。
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 团队必须对其进行性能优化。
另一件事,你的代码没有 运行 on 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/Whosebug/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.
我必须做一些修改。
尝试将此添加到您的列表视图:
physics: const AlwaysScrollableScrollPhysics(),
如果您在模拟器上进行测试,我建议构建发布 APK,将 APK 安装到您的 Android phone 上,然后检查它是否仍然不稳定。模拟器占用资源,所以这可能是一个原因。
最后,您可以尝试减少图片数量、图片类型或尺寸,看看是否仍然卡顿。
否则请在 github 报告此问题,以便 flutter 团队了解。
2 件事
- 考虑使用
FadeInImage.memoryNetwork
而不是cached_network_image
、and/or - 考虑使用
ListView(children: List<Widget> )
而不是ListView.separated(itemBuilder: )
FadeInImage.memoryNetwork
参考 https://flutter.dev/docs/cookbook/images/fading-in-images
当 运行 你的示例代码时,我不禁注意到 cached_network_image
做了一些图像 rescaling/sampling 影响主 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
将 invoke/call 更频繁地使用这些功能,并且现在仅针对完整内容缓存图像(通过 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(),
),
);
}
}
如上所述,您也可以应用这两个建议。
我也看了一个月,经过大量研究,我发现了一行代码,使列表视图或任何列表都非常平滑滚动
只需使用 物理 属性 作为 physics: BouncingScrollPhysics(),
并感受差异
另外,如果你想将它用于 Column,你可以使用 Singlechildscrollview 并且在其中,你可以使用物理 属性.