InteractiveViewer inside PageView - flutter

I'm creating a PageView with a list of images, and I want to add interactiveViewer to each image so it can be resized to view details.
here is what I wrote:
PageView.builder(
dragStartBehavior: DragStartBehavior.start,
physics: _viewing ? NeverScrollableScrollPhysics() : ClampingScrollPhysics(),
controller: _pageController,
itemBuilder: (context, index) {
return Container(
child: Expanded(
child: Image.network(widget.snapshotList[index].imgUrl),
)
);
},
onPageChanged: (index) {
setState(() {
this.position = index;
_transformationController.value = Matrix4.identity();
});
},
itemCount: widget.snapshotList.length,
)
But the two scrollables seem to compete with each other and the behavior is messy.
e.g. once the image is enlarged the scroll gesture also triggers page move,
seems that because the viewport is not enlarged with the image itself.
Any solutions? Thank you anyone out there.

In my case I want to create a simple swipe-able image gallery: swipe horizontally to go from image to image, and use pinch and zoom to zoom in and out. The problem is this: When I zoom in, I can't pan the enlarged image. Instead, the PageView takes over and pages to the next image.
I was able to work around it by using a TransformationController and listening to the onInteractionEnd event on the InteractiveViewer. In that callback, I check whether the image is zoomed in or not. If it's zoomed in, I deactivate paging in the PageView.
Here's a complete sample app that shows how you can implement it:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'InteractiveViewer inside PageView Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final List<ImageProvider> _imageProviders = [
Image.network("https://picsum.photos/id/1001/5616/3744").image,
Image.network("https://picsum.photos/id/1003/1181/1772").image,
Image.network("https://picsum.photos/id/1004/5616/3744").image,
Image.network("https://picsum.photos/id/1005/5760/3840").image
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: EasyImageViewPager(imageProviders: _imageProviders)
),
);
}
}
/// PageView for swiping through a list of images
class EasyImageViewPager extends StatefulWidget {
final List<ImageProvider> imageProviders;
/// Create new instance, using the [imageProviders] to populate the [PageView]
const EasyImageViewPager({ Key? key, required this.imageProviders }) : super(key: key);
#override
_EasyImageViewPagerState createState() => _EasyImageViewPagerState();
}
class _EasyImageViewPagerState extends State<EasyImageViewPager> {
final PageController _pageController = PageController();
bool _pagingEnabled = true;
#override
void dispose() {
_pageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return PageView.builder(
physics: _pagingEnabled ? const PageScrollPhysics() : const NeverScrollableScrollPhysics(),
itemCount: widget.imageProviders.length,
controller: _pageController,
itemBuilder: (context, index) {
final image = widget.imageProviders[index];
return EasyImageView(
imageProvider: image,
onScaleChanged: (scale) {
setState(() {
// Disable paging when image is zoomed-in
_pagingEnabled = scale <= 1.0;
});
},
);
},
);
}
}
/// A full-sized view that displays the given image, supporting pinch & zoom
class EasyImageView extends StatefulWidget {
/// The image to display
final ImageProvider imageProvider;
/// Minimum scale factor
final double minScale;
/// Maximum scale factor
final double maxScale;
/// Callback for when the scale has changed, only invoked at the end of
/// an interaction.
final void Function(double)? onScaleChanged;
/// Create a new instance
const EasyImageView({
Key? key,
required this.imageProvider,
this.minScale = 1.0,
this.maxScale = 5.0,
this.onScaleChanged,
}) : super(key: key);
#override
_EasyImageViewState createState() => _EasyImageViewState();
}
class _EasyImageViewState extends State<EasyImageView> {
final TransformationController _transformationController = TransformationController();
#override
Widget build(BuildContext context) {
return SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: InteractiveViewer(
transformationController: _transformationController,
minScale: widget.minScale,
maxScale: widget.maxScale,
child: Image(image: widget.imageProvider),
onInteractionEnd: (scaleEndDetails) {
double scale = _transformationController.value.getMaxScaleOnAxis();
if (widget.onScaleChanged != null) {
widget.onScaleChanged!(scale);
}
},
)
);
}
}

Related

As a common appbar widget how to change appbar color when page is scrolled Flutter

Good morning friends, I'm trying to make the appbar transparent or white in scrollable
parts.
For me, this solution An efficient way in Flutter to change appbar color when scrolled works, but as the person said, I don't want to use setState continuously and do it in every separate component, so I'm trying to do what is mentioned in the comment. For this reason, I created a common appbar widget so that I can use it in other components. I made the CustomAppBar widget statefull, but I don't know where to add the scrollController. Therefore, I see errors. If anyone has time, can you help?
The code below is the widget where I call CustomAppBar.
import ...
const ExtractionBody({Key? key, required this.goal}) : super(key: key);
final Objective goal;
#override
ExtractionBodyState createState() => ExtractionBodyState();
}
class ExtractionBodyState extends ConsumerState<ExtractionBody> {
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: PreferredSize(
preferredSize: const Size.fromHeight(100),
child: CustomAppBar(
icon: IconButton(
icon: const Icon(PhosphorIcons.xBold),
onPressed: () => Navigator.of(context).pushNamedAndRemoveUntil(
HomePage.routeName,
(route) => false,
),
),
),
),
body: ExtractionRequestContent(
goal: widget.goal, scrollController: _scrollController),
);
}
}
Finally, this is my CustomAppBar code. Thank you very much in advance. and have a good weekend everyone
class CustomAppBar extends StatefulHookConsumerWidget {
static String routeName = "/extraction_body";
const CustomAppBar({Key? key, this.icon})
: preferredSize = const Size.fromWidth(50),
super(key: key);
final Widget? icon;
#override
final Size preferredSize; // default is 56.0
#override
CustomAppBarState createState() => CustomAppBarState();
}
class CustomAppBarState extends ConsumerState<CustomAppBar> {
bool isAppbarCollapsing = false;
final ScrollController _scrollController = ScrollController();
#override
void initState() {
super.initState();
_initializeController();
}
#override
void dispose() {
_scrollController.dispose();
super.dispose();
}
void _initializeController() {
_scrollController.addListener(() {
if (_scrollController.offset == 0.0 &&
!_scrollController.position.outOfRange) {
//Fully expanded situation
if (!mounted) return;
setState(() => isAppbarCollapsing = false);
}
if (_scrollController.offset >= 9.0 &&
!_scrollController.position.outOfRange) {
//Collapsing situation
if (!mounted) return;
setState(() => isAppbarCollapsing = true);
}
});
}
#override
Widget build(BuildContext context) {
return AppBar(
elevation: 0,
backgroundColor:
isAppbarCollapsing ? AppColors.monochromeWhite : Colors.transparent,
title: Text(context.l10n.buttonCancel),
titleSpacing: 4,
leading: widget.icon,
);
}
}
Thanks!
Instead of define ScrollController in CustomAppBar, pass it in constructor like this:
class CustomAppBar extends StatefulHookConsumerWidget {
static String routeName = "/extraction_body";
const CustomAppBar({Key? key, this.icon, required this.scrollController})
: preferredSize = const Size.fromWidth(50),
super(key: key);
final Widget? icon;
final ScrollController scrollController;
#override
final Size preferredSize; // default is 56.0
#override
CustomAppBarState createState() => CustomAppBarState();
}
and use it like this:
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
final ScrollController scrollController = ScrollController(); //<---- define scrollController here
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(100),
child: CustomAppbar(scrollController: scrollController)),
body: ListView.builder(
controller: scrollController,
itemCount: 10,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 100,
width: 100,
color: Colors.red,
margin: EdgeInsets.all(12),
);
},
),
));
}
}

Flutter - PageView - Don't change page if the user still touches the screen

How to update the PageView to trigger onPageChange only on specific conditions?
Here, I don't want to change the current page if the user is still touching the screen. Apart from that, everything should remain the same (ballistic scroll simulation, page limits)
It seems it has to deal with the ScrollPhysics object attached to PageView, but I don't know how to correctly extends it.
Let me know if you need some code, but the question is very general and can refer to any PageView, so you should not need any context.
Minimum Reproductible Example
Here is the translation in dart of the text above. Feel free to update this code to make it achieve the objective.
// main.dart
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(title: _title, home: MyPageView());
}
}
class MyPageView extends StatefulWidget {
const MyPageView({Key? key}) : super(key: key);
#override
State<MyPageView> createState() => _MyPageViewState();
}
class _MyPageViewState extends State<MyPageView> {
#override
Widget build(BuildContext context) {
final PageController controller = PageController();
return Scaffold(
body: SafeArea(
child: PageView.builder(
onPageChanged: (int index) {
// TODO: Don't trigger this function if you still touch the screen
print('onPageChanged index $index, ${controller.page}');
},
allowImplicitScrolling: false,
controller: controller,
itemBuilder: (BuildContext context, int index) {
print('Build Sliver');
return Center(
child: Text('Page $index'),
);
},
)));
}
}
Example of a (bad) solution
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(title: _title, home: MyPageView());
}
}
class MyPageView extends StatefulWidget {
const MyPageView({Key? key}) : super(key: key);
#override
State<MyPageView> createState() => _MyPageViewState();
}
class _MyPageViewState extends State<MyPageView> {
#override
Widget build(BuildContext context) {
final PageController controller = PageController();
return Scaffold(
body: SafeArea(
child: Listener(
onPointerUp: (PointerUpEvent event) {
if (controller.page == null) {
return;
}
if (controller.page! > 0.5) {
//TODO: update the time so it fits the end of the animation
Future.delayed(const Duration(milliseconds: 700), () {
print('Do your custom action onPageChange action here');
});
}
},
child: PageView.builder(
controller: controller,
itemBuilder: (BuildContext context, int index) {
print('Build Sliver');
return Center(
child: Text('Page $index'),
);
},
),
),
));
}
}
This solution triggers an action on the next page, 700ms after the user stops touching the screen.
It does work, but it is a lousy work.
How to account for different screen sizes? 700ms is the maximum amount of time to animate between 2 pages on an iPhone SE.
How to adjust this arbitrary number (700), so it varies according to controller.page (the closer to the next page, the smaller you have to wait).
It doesn't use onHorizontalDragEnd or a similar drag detector, which can result in unwanted behaviour.
You should disable the scrolling entirely on PageView with physics: NeverScrollableScrollPhysics() and detect the scroll left and right on your own with GestureDetector. The GestureDetector.onHorizontalDragEnd will tell which direction the user dragged, to the left or to the right, checking the parameter's DragEndDetails property primaryVelocity. If the value is negative the user dragged to the right and is positive if the user dragged to the left.
To change the page manually just use the PageController methods nextPage and previousPage.
Take a look at the screenshot below and the live demo on DartPad.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
debugShowCheckedModeBanner: false,
scrollBehavior: MyCustomScrollBehavior(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late PageController _pageController;
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onHorizontalDragEnd: (details) => (details.primaryVelocity ?? 0) < 0
? _pageController.nextPage(
duration: const Duration(seconds: 1), curve: Curves.easeInOut)
: _pageController.previousPage(
duration: const Duration(seconds: 1), curve: Curves.easeInOut),
child: PageView(
physics: const NeverScrollableScrollPhysics(),
controller: _pageController,
children: [
Container(
color: const Color.fromARGB(255, 0, 91, 187),
),
Container(
color: const Color.fromARGB(255, 255, 213, 0),
),
],
),
),
);
}
}
class MyCustomScrollBehavior extends MaterialScrollBehavior {
#override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
You can simply use physics: NeverScrollableScrollPhysics() inside PageView() to achieve this kind of behaviour
I struggled with the same solution and built a complex custom gesture controller with drag listeners.
However, your so called bad example seems like the right direction.\
Why have this 700ms at all?\
You already have the onPointerUp event, where you can check the current page by using controller.page.round().\
You can also check that there is a dragging going on at this pointerUp by comparing controller.page==controller.page.floor()

Flutter: How to switch from one page view to another?

I am creating a flutter app where I have a screen which contains a PageView Builder.There are two other screens which are shown depending on the condition in the PageView Builder(i.e. QuizResult and QuizQuestion).
If the index if equal to the number of quiz questions it will show the Quiz Result Page otherwise it will continue showing the next question on the QuizQuestion Page(Have hardcoded the question for this example).
I want to know what logic can I add in the FlatButton widget onPressed in the QuizResult Page so that I can reset the index of the PageView back to the start and can again show the QuizQuestion Page again?
This is the QuizScreen
class QuizScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView.builder(
physics: const NeverScrollableScrollPhysics(),
controller: state.controller,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
if (index == quiz.questions.length) {
return QuizResult();
} else {
return QuizQuestion(question: quiz.questions[index]);
}
},
)
);
}
}
The QuizQuestion Widget looks like this
class QuizQuestion extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(body: Text('Which is the fastest animal?'));
}
}
The QuizResult Widget looks like this
class QuizResult extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(body: FlatButton(onPressed(){ < Logic Here ?? >}, child:Text('PlayAgain')));
}
}
I have used your code to reproduce the issue and then modified it for readability.
All you need is to assign an itemCount. And it needs to be the length of the quiz plus one. We need to add one more page to show the result page.
itemCount: questions.length + 1,
As you already predicted, we need to check the index of the shown page and create a condition based on it.
itemBuilder: (context, index) {
if (index == questions.length) {
return QuizResult(onPressed: onPressed);
}
return QuizQuestion(question: questions[index]);
},
Lastly, you need to jump to the first page using the controller to reset the quiz. The easiest way to do that is: Passing the onPressed function via constructor to QuizResult:
void onPressed() {
controller.jumpToPage(0);
currentPage = 0;
}
Please check the following solution:
main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) => MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const QuizScreen(),
);
}
class QuizScreen extends StatefulWidget {
const QuizScreen({Key? key}) : super(key: key);
#override
State<QuizScreen> createState() => _QuizScreenState();
}
class _QuizScreenState extends State<QuizScreen> {
final PageController controller = PageController();
int currentPage = 0;
List<String> questions = [
'Which is the fastest animal?',
'Which is the slowest animal?',
'Which is the longest animal?',
];
#override
Widget build(BuildContext context) => Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: PageView.builder(
physics: const NeverScrollableScrollPhysics(),
controller: controller,
scrollDirection: Axis.vertical,
itemCount: questions.length + 1,
itemBuilder: (context, index) {
if (index == questions.length) {
return QuizResult(onPressed: onPressed);
}
return QuizQuestion(question: questions[index]);
},
),
),
TextButton(
onPressed: () {
if (currentPage == questions.length) return;
controller.jumpToPage(++currentPage);
},
child: const Text('Next'),
)
],
),
),
);
void onPressed() {
controller.jumpToPage(0);
currentPage = 0;
}
}
class QuizQuestion extends StatelessWidget {
const QuizQuestion({Key? key, required this.question}) : super(key: key);
final String question;
#override
Widget build(BuildContext context) => Center(
child: Text(question),
);
}
class QuizResult extends StatelessWidget {
const QuizResult({Key? key, required this.onPressed}) : super(key: key);
final void Function() onPressed;
#override
Widget build(BuildContext context) => Scaffold(
body: Center(
child: TextButton(
onPressed: onPressed,
child: const Text('Play Again'),
),
),
);
}
You can access the modified source code through GitHub.
If you have further questions, please don't hesitate to write in the comments.

How to scroll the listview or perform any other operation when popupmenu entry appears?

I have created listView which contains 10 container.I trigger the _showCustomMenu() method while longpress the container to show popupmenu.
But could not scroll the listview when popup menu appears.I want to scroll the listview even when popupmenu appears.
This is my code:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(MyApp());
///
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Popup Menu Usage',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Popup Menu Usage'),
);
}
}
///
class MyHomePage extends StatefulWidget {
///
MyHomePage({Key key, this.title}) : super(key: key);
///
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _tapPosition;
void _showCustomMenu() {
final RenderBox overlay = Overlay.of(context).context.findRenderObject();
showMenu(
context: context,
items: <PopupMenuEntry<int>>[PopUpMenuEntry()],
position: RelativeRect.fromRect(
_tapPosition &
const Size(40, 40), // smaller rect, the touch area
Offset.zero & overlay.size // Bigger rect, the entire screen
));
}
void _storePosition(TapDownDetails details) {
_tapPosition = details.globalPosition;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GestureDetector(
onTapDown:_storePosition,
onLongPress: (){
_showCustomMenu();
},
child:ListView.builder(
itemCount: 10,
itemBuilder: (context,index) {
return Container(height: 500,child: Center(child: Text(index.toString(),style: TextStyle(fontSize: 16),),),);
},
),
),
);
}
}
///
// ignore: must_be_immutable
class PopUpMenuEntry extends PopupMenuEntry<int> {
#override
double height = 100;
// height doesn't matter, as long as we are not giving
// initialValue to showMenu().
#override
bool represents(int n) => n == 1 || n == -1;
#override
PopUpMenuEntryState createState() => PopUpMenuEntryState();
}
///
class PopUpMenuEntryState extends State<PopUpMenuEntry> {
void _onPressed() {
Navigator.pop(context);
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
FlatButton(onPressed: _onPressed, child: Text('Copy',style: TextStyle(fontSize: 20),)),
],
);
}
}
This is the Output:
Please help me to solve this or give me suggestion for any other popup widgets to overcome this problem.

Using flutter, my CircleAvatar with a MemoryImage flickers every time I reload a ListView

I am rendering a base64 image using MemoryImage in a CircleAvatar's backgroundImage property and reloading a ListView every so often and every time the ListView reloads, a very obvious flicker in the image appears, starting out as a blue circle then turning into the appropriate image. I was wondering how to get rid of the flickering.
Here is a complete example:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Flickering Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Image Flickering Example'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String img = "\/9j\/4QBqRXhpZgAATU0AKgAAAAgABAEAAAQAAAABAAAASwEBAAQAAAABAAAAZIdpAAQAAAABAAAAPgESAAMAAAABAAAAAAAAAAAAAZIIAAQAAAABAAAAAAAAAAAAAQESAAMAAAABAAAAAAAAAAD\/4AAQSkZJRgABAQAAAQABAAD\/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH\/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH\/wAARCABkAEsDASIAAhEBAxEB\/8QAHgAAAgIDAQEBAQAAAAAAAAAABwgGCQAEBQMBAgr\/xAAvEAACAgICAQMEAgICAQUAAAABAgMEBREGEiEABxMUIjFBFTIII1FhQglDUnGB\/8QAGwEAAwEAAwEAAAAAAAAAAAAAAwQFAgABBgf\/xAAyEQABAwIEAwYFBAMAAAAAAAABAhEhAzEAEkFRBGFxEyIygZHBBUKhsfAUI9HhM1Ky\/9oADAMBAAIRAxEAPwCjBtBYRvYL9XJbwAIJ2UDx+RJrydAdfHkD17xwkSoo8LMG8EeNfE7aBP7BUfbo\/nYI3v17pGrdgQCVL\/sEAqQqkbXaD7wNq2m+4a879fYtxypJ\/YRElST42wI1rWvKuP8AnySe2j4+OFXlEegILSLx9jfH1wAxzy+ja20j6F3BxtPTVk7KQv3KgHUje10y9RohQeuyBrR8NrR9c2xUaWJ1ZVOtjZJLaIYgDQ2QewGzs7\/78eu7E6sVOv7mRyDodGArneurAb0Rsga22\/2B6QwFgyeSJGKk62RtguzrWiOq6\/WgdkDQ9ZTUII1ZuvPZ9fW+NsGIZh06F+f9YC3IaNmoVmgdowVLSdVDJsKsn3IVK7kKBWcBJVj2qSRkdvQ1jls3bLRTqoEZA2jN9zFIwW6EExEsZPt7ynWgZPJUsvmcOtqKaIRg9xKqgDRUsoVeu\/7aB6\/sKQvjW29BKngb9rOPiKlV7GRsWBBBWRV7PJrsCzOVjSJYx8sk8hSOKFTLLJHErutClVSpBcgMNWi2ssBPTrheohlJZ2J9eRG8acsa9evohPI1rQGjtQ2taGifwAoII8gkkaBZn279l7GWEeS5XDax1JZIfpsOR9PctohMksl+Q\/76NVgDGYEEeRlDTzLLRWKvLZk\/t17WUMAYcnm46+RzcUyTVtGWWljFiYrE8SdYhPa7uJ5LUqEV5EjWqIjG1uywVQMNAd3ILF1Dg\/J1G1A7gdvkDa0Ci\/7NM4Xq3qdxPFmU0zP+20\/L\/Ju3R2qdGxUH2T\/O55er2xIcZThqww1KcEVaCCKOOCCvFHDWhjiTQhhjQKsUSwiJVSIKiDSgkgIJMK5QdfvBBOwIWlAOySO\/xyb0dgr3JQ7Q6K6H4xNKDqDP0lBRgUaPcZidCyM6MB9jGIq7lkhKyMhVyJNzwQyaHWLqugVBWyp0fI8R2okGx5+yNR58b\/sZalgXckz66vhkBobbR9tByv6Q81ax7+cHWwsM+9DyS0tZR\/Zta6hxvQJ\/H9d72kj2idfywlKjt4OiFA\/48aAA8nz9p\/G\/scbCZ1by6rCxUn+xLzAg+Ng94ydEE\/snfn17iMrJGUA0I5yBoH\/3k672P23YedN+vIbXqsoEkQRD8nYnzLN6bNhQWFz+Ny9uj42BAWZF\/R7BWP2nZCaJP414\/Q\/ZA8gAetS1UMzwx2YJJ4CxkiWaMyx77dS6bZ4+xUhSy9SQ2iV362o1Uoq6JYspVlX8faCv5OgT+vBG+x8gH0pnJO8XMeTyIxWQZeCRZEJV0aPFYsBlZSGRkZewcEEFQVOtD0XheG\/VKqIC+zKaZUDlzOcyUt4gw715tbAeJ4gcOlCsmcKXlIzZSBlKn8J2Ibnexw30cPbs\/cAgkEaB89tHf5\/AAOifAPYnfkSLA0qdN7FivWrRWpldpbCwxpPMsURKLJMFWZ1jCt8aFyiglgAWZvSpca5byukUWG99ZVj7Ax5FPqU2xDaEvdLTsugQpsfEikdl0qL6JXGveGrdqwy5PE2KpswwuJKk8dtY\/q40LNKJFqOqQdjITGJ3kAbrGzajbFf4dxlMKyAVEjxGkWLQwyHKok7JBtjujxvDrAzE01F2CxEBLkKDhpEnLdmw1GNswMxicGNhFov48Ru7qraKN9w6Oe0yskaqVClRskjGwQSFCHQFysqmII8krvHtS7kOIxKI2iX5B8f9VV4mGlBHF+U4HJ2pHo5erM9mhX61ZJBDcWKObIxSTfR2DHZXT6Uv8YVuu0YowPos4iNYJhJG\/VZkkEpAVwT8TQqCpDCUlQpX\/X47jQHyMTFqlaCQoKSRcEFKp3CmLu+2r4pUyhQCkKCgYzAhQ01D9d2wYMTCvcGFPk6diXGwiECYM8krEkaeP4pVRZJ4JJOxTqxcEtK5ZEPeNftXx8PbWgB5KxOuzrZ0xAJIGtaAswOVkh0bMImjj+Nu8PQTvtoxpkkZY267Lltqo7yIEVT2cwVOQ4D6aHU9ZQE0FnmWvMApIAkhmnWVWAA+51BkGpNacelu2SdRpc9NC3QeWC5TEbWHoP65tuMVXnHsru2v7xqCfP5R5X\/BJ\/Jm2T\/bXjyOututjRK6qVLHbqR2AHliF0BrWyp8aG1+\/a+AZDHAJXmVUCrFKI\/6nW3r1pQNeDsqTokqB31o6Prr43Hq8s3XeglZgSu238swYhSQOq9xo6OyxPYBtD0qg8EbfaPpiQFERp+cxiLpjG6johOvIXYBPX5ADvYPgozD8nx+TvXpS+QYmxHyjOS3opK0dvLFa5mQwi2xpQaWsW+yUmOCRmEZYgRSABTG5jfL+PVC7a0FgRAGUr1Je03nwwY+CQCwBJ0d7LFG7TPDyDK2Fd1JytiVXQsjxlCqB0ZepVk6eWUht78ltH0\/8LSrtauVv8WoM95BgvBJ3BZt5CfHkGlTef3H6dxQPVn32fn0cPVXvHX69UJAjH6BOj1152XHnydljons\/ricOxjWcbiJWBWA4+gZCANyD6eAsiBiPu8n7vwNa0RseiLgKVuxaNnskgd0aazYhhtSSMqL0VZbEcrfJ16\/erAogXzoRhtTgpju8e42giSF4MZj5ZxEzLLahkpR6jf52sRRxIZVdDWiieOSGFZWeNpEmrFKu93RLCC7Fi9wnUQQ8ziaGdPeMBbAgDWmGEm\/k1nONbJY8xcsmrRRq0Q41gJo1QDTizlOTRqqKoOwy1lC6H3Aa2TsejJVzPKOK2uMRV81ZeLK1srkJIrEn8hAseMsYOJIVWwsjRKBkHjspVaKXbuiv3jhkHMx+Lxbc6nhsG\/WnfhvHJ6cbpWvL8cmb5eawMqjGsrv1yMhYxzCOL6aNO7ysIZweNzXuRcJitTVmmhw\/LUiwsEs73bItX+CPft1bFiKrQfFYhoUNxfmr5R\/r45KeNn+aU11atGlVypq0gtOWUqQFjwxICh4gC4Li5IZ8Fp1KlPvU1lJzGUqKXAXq7FwCYaS4GHD9qsbkuYcfFy\/BBFkVsISKizLFYqSMr1LfSUyfGJtzxhVmlDiFbKPGs8UUZZk9sbBcnrOQQpBUN1KlQV0ew2Na8gAH8gaPqY\/4scTyE2LzCzRVfgxwx1eNVsU7EzrNFLYpbjhtz2YFrRSTwJ8levXfqKtd5LOOvRV3Hj4MAupEZ27P5WJ1AXu3SMAxsdRJ1j3vz03ob0PF8bwVMcTVTSSAgKSUhLkB0pUQJs5s8CNgL\/D8arskdorvMxJuWUQC25Ac7ktYlqGY6Gu7oCRLMQ+wy7MapCQN6BIEagkggAa2D4HUr0nRh1GjIkYb9\/aGDgDXTe1UaH5HZh+B56FGAtVJKkMbWQJJIJAF+1GhKkAHaxAgH8KGA8L4kVSnG8so6qBHMsKqfAA+NZQOwZeoCud7JJY\/wDaj1cV9BF+mrPrqIe5dsL44clOT4mYA6+BHJ0rdTt+wB8hgr6J2Rr8eD+EMFP62\/ekPlP5G+JHA2C0duZOib39w1o7\/qF2QR1DWcV6ETpD2iDKA6SqVBDKzS9QVKgEbBjbRP586Oz61pfbTgmVVlyfDOMZEyCuGN3B420W7Aqe4lrOWKjRBb7RobP3AFjhOJHDLWpSCrMnLBAIkF2IP51gHEUTWQEhQSys0i8NcW9DhIuLCOCSKiwEcTHUDb0EZidoA2x\/tP40SWlJHV2lJEa9taD\/AMHxe91HWLDYeRVk7FZm+grF0kXa9omG1lAA77ZNnb6scwPtX7c0qlSCrwjjFSIfGBFUwuPqDtKds4SvWi32Ys7EAMxdnYj8mb4L2a9tpJGqjiOMirR0qa1atRZqcUCxzWY1jrRU5YViT4kjhRFQKEjjVSpQD04r4ogAtRqSQ8p0ZupJMnUvGFBwK3BK0hgoADNJJTrDeEvGvIDFfmQT+R9xZ56gZPl4Pwv4yOymOdeRe4SyjuAD2gZQWZAPwJE2CGDCy4\/G2eN8fv8AwxNyLGZRsXDdRFjvdcpA122tdoWEscd58Lj5m6gblxkSJ2+lVvTYQ\/4x+0WZuULVnjN+rrH2op5MVy7mWClnMdyvPTWe3h8\/RnnjhMl34YJZpokNuVQihtA48X\/xt9rTj8dE\/HLUuQrQ17NZpeR8llRcqcRdqpZmSfLyLM0ZvWY1Myy\/GJ32O2mUZ+I0jl\/brBrMEm4a+cO4O2O1cKsfMiS4lW4JgJNvzbEk\/wAPIKWQxGfoWmRcrYp4yS1WBYOywC\/WtyIUAVVH1ePAMe0SScLG7Ort6fM4WFOquIUYJH2Vinbt0Ukn\/Z\/5H7h\/0R4H49Cv2o9t\/bPgeSmu8auY7H5F4Y4MxBZz8luxFjZIZvjrNVt3pPpWkysVCyliWETv1atG6pK0ZaiPAYu7FDbeBJzYhhlEzfODIrxqUY9J1XynX8KN\/k7OyZtbLWqrqhKhnKYUA8BI3OgS0xEPjOYoAS7tzIElwLCZ29cfy\/QxRJXhYlVV4jIBoEN8r\/IrEa0C\/wAmzrYHcN+l9fuXKUKVmx8k6BGnXyWQgFYYE8E61pgT+QpI156gkW5TlTUqNetG6vLXopCzdgNvDWVS35\/O1P8AbRYk7H7IevcjuX2mmksPvbugVz16\/JKAAR12Nr4bwp0NliPDIQVdPu7EDXf662w+FgACS341xZ28o5NZJ7kYOlIzfJHIAdMB\/wDEV4dFjpVJ+QOWPna6P2kn1EOQe9t9j8fHq1Ybigje7NqWWGaVlhSWKEdoTJV38wEwmSWR0R4lRH+RU7Fy5kLseNq2EFi0SEaaSRYwRC7kM8KSOftjYApE47ggjX3CRYjA53G05\/maveDutiR1tQwOrJ9GDDBFPKHswkRzETt8RLCNGhUSO0ZE0EAAqLQAxLPYaNf8vjOckskWgmIgOAJJn+7RZB7E5CpnuO4yHMGDIW7L2pr0mSVbbNPLkbQX4o5hIlavFXSusVaFIq8Ji3DCvjTCYK3Q\/l7uMFatAKebuVojWjgRPpILDxiEiNAoEQQR\/r7lYNpwR6pJ5\/708y4dxaTHcXyNjjxjjhhku1kmp3rKSZKN7aC6rQ264Isz1RYx08MxjVZILaEq4Yf\/ABX988fxXFRxZCvPkMDkY1uz1qCwrkMTl1iWG01MTWIo7VS1KsSzQ2LcLCD4LlYpZWxWyXKnCEIFR4XCQLadA2wsw3xqnUFRa0CV00glOpcsWkTyZ5iHxa9l50xeUheCUxRWbEKoQraTcfRvA8IHZdknYJIPkEgmHjUoTkcaraZ1zODTkvxQo0cFeR5W4y9QH5XVws3FZLsJCRxxHKzQJBGIGms165T\/ACh4xlOTTcexdENJRkoLTvXJJJo7UU0EM3zmpD9NPUdbLWagSy5cLXW2Y\/p7UXol8t557lUuGWPcbhXI6lHM8RqyWeQUr1bDpj5PbqpDmMrmJUgy1eSvG\/H7065yxK1+pdmxFfORd7mTjw+NsAFFQKXhyGeLkH7GBd9scLlJFiAUknQulnueuxd8OT71e+3Hv8e\/avk\/unn8dmOQ08FUrVqmEwz1ocjkMlmblbFY6L552VKVCK9chly1\/wCG3Lj8THcux0MhLFHTsKrhf\/XB4dBiqMU3sJZmljgVXkf3JrxOzAn+6DghAcf1ZtkyMDISSx9CPD+8t\/3PxiY33lxuG5BhJkIOOyGIxMuBvKkgld7mFsoKVgosfWNp1ZIt7jQq05lWz3R\/wo9p+a895Fyvh3ubS9u+PZ2xVyFPhuF4HjMtiMLYlx9QZVMbat+5mGeGldyy3slWxkGJxuPwkVxcNi6VfGUKkSt0xSYpWCC7hTBQIgWOZjciPO+BHhhBqUhVgN3qiWcjVCkuCDYy48grWbzCzfKquTp3VmDfpiygjQA\/8XBIHgg\/g61DjJJ9N0HYljYC6BMjO1uUhFXXZm\/2D7OvnR87C9mhq8Z4XSmaX+OoySFPjZbLyZGLqzq5PxZCexXEg6L8ciIsgAZFfUkhMmq2+O4uD4K8+OpQRtsVqsaQVlaRmaRlSuojEjHuzhQoZm7FmJ36B2w0QpVrx9gfeCza42aaj8wEFyATtzDe2F09vfaLnvM+VQvVxgxNLHSXHvZHkRmxUEbjF5y5UhhgavJkrrWVxs9aJ6NCzXr3bOOrXJqr5OgJyrzPiOd9ueQvxjkiVlvxV4bSyUpJbOPuV5mnjSxj8g0MVTJVTLXmgF3HtYovPDPBHZeWvMsZExHvF7d8bzceJyXI46tjK1yar2KOX+jf6YWJJA+TOPGKgaIK6uli7FJ8k1SMLJJdgQz\/AJ5dwnvAuFyWJKS4XE8fg47Uy717MEtizDYuZC9dxrZHHVZkigu3Wx4mp\/V0bbY9m+pmgmlqxkK6oSmrUQE0FABKRTWC7kP2hXlU5CoCExEsSRoyZ1UkqdSXJOdJB7qT4AnMky0qVoWnC5UYMVIjJeweBztayGis0c7hqGWpzRuv3xSQ3IJl+9H6lWR1ZOwKEd\/UgrcM9qrKWWp4e37eZK21+VLfF5+mGXI2khFSZ8JZWxjq2Noyxlv4nBx8cgswT2a7zxuKdqlq5riue4tN9RDG+TwnZmFmBJHtU4UriZpMlEkYWJIyJw1yIPWaKATTLTNiGudyjYSwi9WXTbJ\/Y3oEnR1sn9D\/AIBIBBHrvMCHQs5TMKLWEFNgRzD7bkoJQoKYZhqwduSr\/UjliV4r2WlyfIeOtjc7x3I0JbUtTL8huSS4bJQYiPD5S7H82LaHKQ2zNyj+Oq1qkeXlSvUuZTJtPVd5KFixHhXEFxbUL13O25Wgr1dVcIwoUjMjPPKJbwaxdtRrOY5KtqucVOFiVpFYSNClbVea3Tk+WhZlqOCDqOQiNmDb++NiV8\/jYUMfOiNnZ\/8Abn3Cyis1ezkZqVmIJIgjeR4LYUnZ+N+8QMble8c3dSj7USAuEGsrIDkEDyN\/MC7QNMaK85JcgqbQDQDQCYdyxJJPIN6\/s77XW8RNhp+IcRzFAV8fUxuH5rxLB8xwGPjx8lZq5kr5OoudyEiRV06yXuSSypbWO6WZ4liYrxzWMdFBRxPE+ISUK0EEUDLmLnHkBEKGaOLDQcXz0VCCKwZYoI1y1wvCkcztE8jQRBziPKL+TqTST9ZTXeMCVQqySqwkfbxr1Qsg6gGMRBl13BbbNMVzcRUFp2U\/sNHIp\/8A1SARsefP\/wB+gmq8EqMks77TMTyfrbGCk6h7Bw7xazFhzi++KeEw1Sw8aymdhIoY\/wC38GTZbqCpAA148eCSfLeRJMXw7BWJGaeq0xVo1X5HDgBye2gykDYUDwNePWes9cUSASCQdxBvguoGjGNNMTWrhcRQjT6TG0oT8qqGWtEXG0LkiRlZyew35YgbJA2FKySKVukRbTjbp0bfXSl1B+0q2+sYUjt1KkggggDPWegkk3JPXHBr19hgdcv5jmcdi8nYpNWrtVgssojg0JDEjshlk7\/OSCo20csbkkt276YBDimcv35pJbDoWmt2HYBToF2V2692cjzIQNklVVQpAB3nrPTFDXz9sYqaeftgqQsQSPHgjzr87dD5A0PBOxoDyBvevUqwjtDfoMh0Szg\/rwAT+tfnQB3+gPWes9GX4T5fcYxTunp7Ycjg2TtUq9AQMoFh7IlDLsMIkg6+AR+jpt7B9GCWJGctojsEYgE6BZFJA3s6G\/GyTr8k+s9Z6Rwyq\/r\/ANHH\/9k=";
Widget body = Text("...");
void _updateListView() {
Widget listView = ListView.builder(
itemCount: 1,
itemBuilder: (BuildContext context, int index){
return Card(
child: CircleAvatar(
backgroundImage: MemoryImage(base64Decode(img)),
),
);
},
);
setState(() {
body = listView;
});
}
Timer listRefreshTimer;
void listRefresher(){
const oneSec = const Duration(seconds: 1);
listRefreshTimer = new Timer.periodic(oneSec,(Timer t){
_updateListView();
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
listRefresher();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body:body
);
}
}
Move the result of the decoding into a variable, so it won't be re-run on every state update:
class _MyHomePageState extends State<MyHomePage> {
final img = base64Decode("\/9j\/4QBqRXhpZgAATU0AKgAAAAgABAEAAAQAAAABAAAASwEBAAQAAAABAAAAZIdpAAQAAAABAAAAPgESAAMAAAABAAAAAAAAAAAAAZIIAAQAAAABAAAAAAAAAAAAAQESAAMAAAABAAAAAAAAAAD\/4AAQSkZJRgABAQAAAQABAAD\/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH\/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH\/wAARCABkAEsDASIAAhEBAxEB\/8QAHgAAAgIDAQEBAQAAAAAAAAAABwgGCQAEBQMBAgr\/xAAvEAACAgICAQMEAgICAQUAAAABAgMEBREGEiEABxMUIjFBFTIII1FhQglDUnGB\/8QAGwEAAwEAAwEAAAAAAAAAAAAAAwQFAgABBgf\/xAAyEQABAwIEAwYFBAMAAAAAAAABAhEhAzEAEkFRBGFxEyIygZHBBUKhsfAUI9HhM1Ky\/9oADAMBAAIRAxEAPwCjBtBYRvYL9XJbwAIJ2UDx+RJrydAdfHkD17xwkSoo8LMG8EeNfE7aBP7BUfbo\/nYI3v17pGrdgQCVL\/sEAqQqkbXaD7wNq2m+4a879fYtxypJ\/YRElST42wI1rWvKuP8AnySe2j4+OFXlEegILSLx9jfH1wAxzy+ja20j6F3BxtPTVk7KQv3KgHUje10y9RohQeuyBrR8NrR9c2xUaWJ1ZVOtjZJLaIYgDQ2QewGzs7\/78eu7E6sVOv7mRyDodGArneurAb0Rsga22\/2B6QwFgyeSJGKk62RtguzrWiOq6\/WgdkDQ9ZTUII1ZuvPZ9fW+NsGIZh06F+f9YC3IaNmoVmgdowVLSdVDJsKsn3IVK7kKBWcBJVj2qSRkdvQ1jls3bLRTqoEZA2jN9zFIwW6EExEsZPt7ynWgZPJUsvmcOtqKaIRg9xKqgDRUsoVeu\/7aB6\/sKQvjW29BKngb9rOPiKlV7GRsWBBBWRV7PJrsCzOVjSJYx8sk8hSOKFTLLJHErutClVSpBcgMNWi2ssBPTrheohlJZ2J9eRG8acsa9evohPI1rQGjtQ2taGifwAoII8gkkaBZn279l7GWEeS5XDax1JZIfpsOR9PctohMksl+Q\/76NVgDGYEEeRlDTzLLRWKvLZk\/t17WUMAYcnm46+RzcUyTVtGWWljFiYrE8SdYhPa7uJ5LUqEV5EjWqIjG1uywVQMNAd3ILF1Dg\/J1G1A7gdvkDa0Ci\/7NM4Xq3qdxPFmU0zP+20\/L\/Ju3R2qdGxUH2T\/O55er2xIcZThqww1KcEVaCCKOOCCvFHDWhjiTQhhjQKsUSwiJVSIKiDSgkgIJMK5QdfvBBOwIWlAOySO\/xyb0dgr3JQ7Q6K6H4xNKDqDP0lBRgUaPcZidCyM6MB9jGIq7lkhKyMhVyJNzwQyaHWLqugVBWyp0fI8R2okGx5+yNR58b\/sZalgXckz66vhkBobbR9tByv6Q81ax7+cHWwsM+9DyS0tZR\/Zta6hxvQJ\/H9d72kj2idfywlKjt4OiFA\/48aAA8nz9p\/G\/scbCZ1by6rCxUn+xLzAg+Ng94ydEE\/snfn17iMrJGUA0I5yBoH\/3k672P23YedN+vIbXqsoEkQRD8nYnzLN6bNhQWFz+Ny9uj42BAWZF\/R7BWP2nZCaJP414\/Q\/ZA8gAetS1UMzwx2YJJ4CxkiWaMyx77dS6bZ4+xUhSy9SQ2iV362o1Uoq6JYspVlX8faCv5OgT+vBG+x8gH0pnJO8XMeTyIxWQZeCRZEJV0aPFYsBlZSGRkZewcEEFQVOtD0XheG\/VKqIC+zKaZUDlzOcyUt4gw715tbAeJ4gcOlCsmcKXlIzZSBlKn8J2Ibnexw30cPbs\/cAgkEaB89tHf5\/AAOifAPYnfkSLA0qdN7FivWrRWpldpbCwxpPMsURKLJMFWZ1jCt8aFyiglgAWZvSpca5byukUWG99ZVj7Ax5FPqU2xDaEvdLTsugQpsfEikdl0qL6JXGveGrdqwy5PE2KpswwuJKk8dtY\/q40LNKJFqOqQdjITGJ3kAbrGzajbFf4dxlMKyAVEjxGkWLQwyHKok7JBtjujxvDrAzE01F2CxEBLkKDhpEnLdmw1GNswMxicGNhFov48Ru7qraKN9w6Oe0yskaqVClRskjGwQSFCHQFysqmII8krvHtS7kOIxKI2iX5B8f9VV4mGlBHF+U4HJ2pHo5erM9mhX61ZJBDcWKObIxSTfR2DHZXT6Uv8YVuu0YowPos4iNYJhJG\/VZkkEpAVwT8TQqCpDCUlQpX\/X47jQHyMTFqlaCQoKSRcEFKp3CmLu+2r4pUyhQCkKCgYzAhQ01D9d2wYMTCvcGFPk6diXGwiECYM8krEkaeP4pVRZJ4JJOxTqxcEtK5ZEPeNftXx8PbWgB5KxOuzrZ0xAJIGtaAswOVkh0bMImjj+Nu8PQTvtoxpkkZY267Lltqo7yIEVT2cwVOQ4D6aHU9ZQE0FnmWvMApIAkhmnWVWAA+51BkGpNacelu2SdRpc9NC3QeWC5TEbWHoP65tuMVXnHsru2v7xqCfP5R5X\/BJ\/Jm2T\/bXjyOututjRK6qVLHbqR2AHliF0BrWyp8aG1+\/a+AZDHAJXmVUCrFKI\/6nW3r1pQNeDsqTokqB31o6Prr43Hq8s3XeglZgSu238swYhSQOq9xo6OyxPYBtD0qg8EbfaPpiQFERp+cxiLpjG6johOvIXYBPX5ADvYPgozD8nx+TvXpS+QYmxHyjOS3opK0dvLFa5mQwi2xpQaWsW+yUmOCRmEZYgRSABTG5jfL+PVC7a0FgRAGUr1Je03nwwY+CQCwBJ0d7LFG7TPDyDK2Fd1JytiVXQsjxlCqB0ZepVk6eWUht78ltH0\/8LSrtauVv8WoM95BgvBJ3BZt5CfHkGlTef3H6dxQPVn32fn0cPVXvHX69UJAjH6BOj1152XHnydljons\/ricOxjWcbiJWBWA4+gZCANyD6eAsiBiPu8n7vwNa0RseiLgKVuxaNnskgd0aazYhhtSSMqL0VZbEcrfJ16\/erAogXzoRhtTgpju8e42giSF4MZj5ZxEzLLahkpR6jf52sRRxIZVdDWiieOSGFZWeNpEmrFKu93RLCC7Fi9wnUQQ8ziaGdPeMBbAgDWmGEm\/k1nONbJY8xcsmrRRq0Q41gJo1QDTizlOTRqqKoOwy1lC6H3Aa2TsejJVzPKOK2uMRV81ZeLK1srkJIrEn8hAseMsYOJIVWwsjRKBkHjspVaKXbuiv3jhkHMx+Lxbc6nhsG\/WnfhvHJ6cbpWvL8cmb5eawMqjGsrv1yMhYxzCOL6aNO7ysIZweNzXuRcJitTVmmhw\/LUiwsEs73bItX+CPft1bFiKrQfFYhoUNxfmr5R\/r45KeNn+aU11atGlVypq0gtOWUqQFjwxICh4gC4Li5IZ8Fp1KlPvU1lJzGUqKXAXq7FwCYaS4GHD9qsbkuYcfFy\/BBFkVsISKizLFYqSMr1LfSUyfGJtzxhVmlDiFbKPGs8UUZZk9sbBcnrOQQpBUN1KlQV0ew2Na8gAH8gaPqY\/4scTyE2LzCzRVfgxwx1eNVsU7EzrNFLYpbjhtz2YFrRSTwJ8levXfqKtd5LOOvRV3Hj4MAupEZ27P5WJ1AXu3SMAxsdRJ1j3vz03ob0PF8bwVMcTVTSSAgKSUhLkB0pUQJs5s8CNgL\/D8arskdorvMxJuWUQC25Ac7ktYlqGY6Gu7oCRLMQ+wy7MapCQN6BIEagkggAa2D4HUr0nRh1GjIkYb9\/aGDgDXTe1UaH5HZh+B56FGAtVJKkMbWQJJIJAF+1GhKkAHaxAgH8KGA8L4kVSnG8so6qBHMsKqfAA+NZQOwZeoCud7JJY\/wDaj1cV9BF+mrPrqIe5dsL44clOT4mYA6+BHJ0rdTt+wB8hgr6J2Rr8eD+EMFP62\/ekPlP5G+JHA2C0duZOib39w1o7\/qF2QR1DWcV6ETpD2iDKA6SqVBDKzS9QVKgEbBjbRP586Oz61pfbTgmVVlyfDOMZEyCuGN3B420W7Aqe4lrOWKjRBb7RobP3AFjhOJHDLWpSCrMnLBAIkF2IP51gHEUTWQEhQSys0i8NcW9DhIuLCOCSKiwEcTHUDb0EZidoA2x\/tP40SWlJHV2lJEa9taD\/AMHxe91HWLDYeRVk7FZm+grF0kXa9omG1lAA77ZNnb6scwPtX7c0qlSCrwjjFSIfGBFUwuPqDtKds4SvWi32Ys7EAMxdnYj8mb4L2a9tpJGqjiOMirR0qa1atRZqcUCxzWY1jrRU5YViT4kjhRFQKEjjVSpQD04r4ogAtRqSQ8p0ZupJMnUvGFBwK3BK0hgoADNJJTrDeEvGvIDFfmQT+R9xZ56gZPl4Pwv4yOymOdeRe4SyjuAD2gZQWZAPwJE2CGDCy4\/G2eN8fv8AwxNyLGZRsXDdRFjvdcpA122tdoWEscd58Lj5m6gblxkSJ2+lVvTYQ\/4x+0WZuULVnjN+rrH2op5MVy7mWClnMdyvPTWe3h8\/RnnjhMl34YJZpokNuVQihtA48X\/xt9rTj8dE\/HLUuQrQ17NZpeR8llRcqcRdqpZmSfLyLM0ZvWY1Myy\/GJ32O2mUZ+I0jl\/brBrMEm4a+cO4O2O1cKsfMiS4lW4JgJNvzbEk\/wAPIKWQxGfoWmRcrYp4yS1WBYOywC\/WtyIUAVVH1ePAMe0SScLG7Ort6fM4WFOquIUYJH2Vinbt0Ukn\/Z\/5H7h\/0R4H49Cv2o9t\/bPgeSmu8auY7H5F4Y4MxBZz8luxFjZIZvjrNVt3pPpWkysVCyliWETv1atG6pK0ZaiPAYu7FDbeBJzYhhlEzfODIrxqUY9J1XynX8KN\/k7OyZtbLWqrqhKhnKYUA8BI3OgS0xEPjOYoAS7tzIElwLCZ29cfy\/QxRJXhYlVV4jIBoEN8r\/IrEa0C\/wAmzrYHcN+l9fuXKUKVmx8k6BGnXyWQgFYYE8E61pgT+QpI156gkW5TlTUqNetG6vLXopCzdgNvDWVS35\/O1P8AbRYk7H7IevcjuX2mmksPvbugVz16\/JKAAR12Nr4bwp0NliPDIQVdPu7EDXf662w+FgACS341xZ28o5NZJ7kYOlIzfJHIAdMB\/wDEV4dFjpVJ+QOWPna6P2kn1EOQe9t9j8fHq1Ybigje7NqWWGaVlhSWKEdoTJV38wEwmSWR0R4lRH+RU7Fy5kLseNq2EFi0SEaaSRYwRC7kM8KSOftjYApE47ggjX3CRYjA53G05\/maveDutiR1tQwOrJ9GDDBFPKHswkRzETt8RLCNGhUSO0ZE0EAAqLQAxLPYaNf8vjOckskWgmIgOAJJn+7RZB7E5CpnuO4yHMGDIW7L2pr0mSVbbNPLkbQX4o5hIlavFXSusVaFIq8Ji3DCvjTCYK3Q\/l7uMFatAKebuVojWjgRPpILDxiEiNAoEQQR\/r7lYNpwR6pJ5\/708y4dxaTHcXyNjjxjjhhku1kmp3rKSZKN7aC6rQ264Isz1RYx08MxjVZILaEq4Yf\/ABX988fxXFRxZCvPkMDkY1uz1qCwrkMTl1iWG01MTWIo7VS1KsSzQ2LcLCD4LlYpZWxWyXKnCEIFR4XCQLadA2wsw3xqnUFRa0CV00glOpcsWkTyZ5iHxa9l50xeUheCUxRWbEKoQraTcfRvA8IHZdknYJIPkEgmHjUoTkcaraZ1zODTkvxQo0cFeR5W4y9QH5XVws3FZLsJCRxxHKzQJBGIGms165T\/ACh4xlOTTcexdENJRkoLTvXJJJo7UU0EM3zmpD9NPUdbLWagSy5cLXW2Y\/p7UXol8t557lUuGWPcbhXI6lHM8RqyWeQUr1bDpj5PbqpDmMrmJUgy1eSvG\/H7065yxK1+pdmxFfORd7mTjw+NsAFFQKXhyGeLkH7GBd9scLlJFiAUknQulnueuxd8OT71e+3Hv8e\/avk\/unn8dmOQ08FUrVqmEwz1ocjkMlmblbFY6L552VKVCK9chly1\/wCG3Lj8THcux0MhLFHTsKrhf\/XB4dBiqMU3sJZmljgVXkf3JrxOzAn+6DghAcf1ZtkyMDISSx9CPD+8t\/3PxiY33lxuG5BhJkIOOyGIxMuBvKkgld7mFsoKVgosfWNp1ZIt7jQq05lWz3R\/wo9p+a895Fyvh3ubS9u+PZ2xVyFPhuF4HjMtiMLYlx9QZVMbat+5mGeGldyy3slWxkGJxuPwkVxcNi6VfGUKkSt0xSYpWCC7hTBQIgWOZjciPO+BHhhBqUhVgN3qiWcjVCkuCDYy48grWbzCzfKquTp3VmDfpiygjQA\/8XBIHgg\/g61DjJJ9N0HYljYC6BMjO1uUhFXXZm\/2D7OvnR87C9mhq8Z4XSmaX+OoySFPjZbLyZGLqzq5PxZCexXEg6L8ciIsgAZFfUkhMmq2+O4uD4K8+OpQRtsVqsaQVlaRmaRlSuojEjHuzhQoZm7FmJ36B2w0QpVrx9gfeCza42aaj8wEFyATtzDe2F09vfaLnvM+VQvVxgxNLHSXHvZHkRmxUEbjF5y5UhhgavJkrrWVxs9aJ6NCzXr3bOOrXJqr5OgJyrzPiOd9ueQvxjkiVlvxV4bSyUpJbOPuV5mnjSxj8g0MVTJVTLXmgF3HtYovPDPBHZeWvMsZExHvF7d8bzceJyXI46tjK1yar2KOX+jf6YWJJA+TOPGKgaIK6uli7FJ8k1SMLJJdgQz\/AJ5dwnvAuFyWJKS4XE8fg47Uy717MEtizDYuZC9dxrZHHVZkigu3Wx4mp\/V0bbY9m+pmgmlqxkK6oSmrUQE0FABKRTWC7kP2hXlU5CoCExEsSRoyZ1UkqdSXJOdJB7qT4AnMky0qVoWnC5UYMVIjJeweBztayGis0c7hqGWpzRuv3xSQ3IJl+9H6lWR1ZOwKEd\/UgrcM9qrKWWp4e37eZK21+VLfF5+mGXI2khFSZ8JZWxjq2Noyxlv4nBx8cgswT2a7zxuKdqlq5riue4tN9RDG+TwnZmFmBJHtU4UriZpMlEkYWJIyJw1yIPWaKATTLTNiGudyjYSwi9WXTbJ\/Y3oEnR1sn9D\/AIBIBBHrvMCHQs5TMKLWEFNgRzD7bkoJQoKYZhqwduSr\/UjliV4r2WlyfIeOtjc7x3I0JbUtTL8huSS4bJQYiPD5S7H82LaHKQ2zNyj+Oq1qkeXlSvUuZTJtPVd5KFixHhXEFxbUL13O25Wgr1dVcIwoUjMjPPKJbwaxdtRrOY5KtqucVOFiVpFYSNClbVea3Tk+WhZlqOCDqOQiNmDb++NiV8\/jYUMfOiNnZ\/8Abn3Cyis1ezkZqVmIJIgjeR4LYUnZ+N+8QMble8c3dSj7USAuEGsrIDkEDyN\/MC7QNMaK85JcgqbQDQDQCYdyxJJPIN6\/s77XW8RNhp+IcRzFAV8fUxuH5rxLB8xwGPjx8lZq5kr5OoudyEiRV06yXuSSypbWO6WZ4liYrxzWMdFBRxPE+ISUK0EEUDLmLnHkBEKGaOLDQcXz0VCCKwZYoI1y1wvCkcztE8jQRBziPKL+TqTST9ZTXeMCVQqySqwkfbxr1Qsg6gGMRBl13BbbNMVzcRUFp2U\/sNHIp\/8A1SARsefP\/wB+gmq8EqMks77TMTyfrbGCk6h7Bw7xazFhzi++KeEw1Sw8aymdhIoY\/wC38GTZbqCpAA148eCSfLeRJMXw7BWJGaeq0xVo1X5HDgBye2gykDYUDwNePWes9cUSASCQdxBvguoGjGNNMTWrhcRQjT6TG0oT8qqGWtEXG0LkiRlZyew35YgbJA2FKySKVukRbTjbp0bfXSl1B+0q2+sYUjt1KkggggDPWegkk3JPXHBr19hgdcv5jmcdi8nYpNWrtVgssojg0JDEjshlk7\/OSCo20csbkkt276YBDimcv35pJbDoWmt2HYBToF2V2692cjzIQNklVVQpAB3nrPTFDXz9sYqaeftgqQsQSPHgjzr87dD5A0PBOxoDyBvevUqwjtDfoMh0Szg\/rwAT+tfnQB3+gPWes9GX4T5fcYxTunp7Ycjg2TtUq9AQMoFh7IlDLsMIkg6+AR+jpt7B9GCWJGctojsEYgE6BZFJA3s6G\/GyTr8k+s9Z6Rwyq\/r\/ANHH\/9k=");
Widget body = Text("...");
void _updateListView() {
Widget listView = ListView.builder(
itemCount: 1,
itemBuilder: (BuildContext context, int index) {
return Card(
child: CircleAvatar(
maxRadius: 40,
backgroundImage: MemoryImage(img),
Don't use CircleAvatar. Switch to plain Image widget instead, and set gaplessPlayback to true.
Image.memory(
thumbData,
gaplessPlayback: true,
)