Reputation: 285
I have created a list view with network images and when I am trying to scroll the listview it's scrolling is not smooths it feels like jerking. For caching I have used cached_network_image: any, this library itself working fine but listview is not getting scrolled smooth.
I know we can achieve this with Future widget but dont know how to return cached image with 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),
);
}
}
Edit: After changing build configuration to Release still same, jerking.
Upvotes: 14
Views: 27360
Reputation: 678
I was also looking at it for a month and after a lot of research I found a single line code that makes a listview or any list a buttery smooth scrolling
Just use physics property as physics: BouncingScrollPhysics(),
and feel the difference
also if you want it for a Column you can use Singlechildscrollview and in that, you can use the physics property.
Upvotes: 5
Reputation: 4866
2 things
FadeInImage.memoryNetwork
instead of cached_network_image
, and/orListView(children: List<Widget> )
instead of ListView.separated(itemBuilder: )
FadeInImage.memoryNetwork
Ref https://flutter.dev/docs/cookbook/images/fading-in-images
When running your example code, I can't help to notice that cached_network_image
doing some image rescaling/sampling affecting main UI thread, it's likely that this package is doing computational-heavy task on main thread. Using the official cooking book yields better result for me (Android emulator), full sample code (you may want to change kTransparentImage
to some other loading icon)
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> )
Ref https://docs.flutter.io/flutter/widgets/ListView-class.html
Secondly, if you know in advance that you are going to have this finite not-so-long list, maybe you want to use ListView(children: List<Widget> )
instead of ListView.separated(itemBuilder: )
, because itemBuilder
will invoke/call the functions more often, and right now images are cached (either by FadeInImage.memoryNetwork
or cached_network_image
) for full content only, not for thumbnail, @user1462442 mention source image size, and I agree with that assessment. What we can do is to reduce the invocation to a number as low as possible.
E.g code:
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(),
),
);
}
}
As said, you can apply both of these recommendations as well.
Upvotes: 18
Reputation: 555
Try adding this to your listview:
physics: const AlwaysScrollableScrollPhysics(),
If you are testing on an emulator, I suggest to build the release APK, install the APK on your Android phone and check to see if it is still jerky. Emulator are resource hogging, so it might be a cause.
Lastly, you can try to reduce the image numbers, image types or size to see if it is still laggy.
Else report this issue at github, so that the flutter team is aware.
Upvotes: 1
Reputation: 8202
I do not think there is a good solution right now other than reduce the source image size. I took a look at your image list and some the images are quite huge.
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 downscaling is quite slow. Flutter team have to optimize it for performance.
Another thing, your code does not run 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/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.
I have to make a few modifications.
Upvotes: 0