Assets do not load but when I hot reload - image

I am new to flutter. I am getting image from backend and displaying those images on the screen using Hero and FadeInImage.
I ave added the hyperlinks in the images and generating the list of images after hitting the API.
child: Hero(
tag: tag,
child: FadeInImage(
width: 130.0,
height: 186.0,
placeholder: AssetImage('assets/images/splash1.png'),
fit: BoxFit.cover,
// onTap: _launchUrl(),
image: NetworkImage(
(merchant.logo)),
// fit: BoxFit.cover,
),
),
),
),
when I run my app, the images are not loaded; the screen is empty. But when I hot reload it shows.
...List.generate(
merchantsList.length,
(index) {
print(merchantsList.length);
print(index);
return MerchantCard(merchant: merchantsList[index]);

You can use placeholder image and also you can add Future Builder concept and Please once check the Future Concept.
#override
Widget build(BuildContext context) {
return new FutureBuilder(
future: _loadImage(),
builder: (BuildContext context, AsyncSnapshot<Image> image) {
if (image.hasData) {
return image.data; // image is ready
} else {
return new Container(); // placeholder
}
},
);
}

The problem was actually widget was built before values are populated in the list. I used setState on my listPopulated function and it worked perfectly ok.

Related

flutter - bad perf- advice

I'm developing my first app with flutter. At some point I was wondering :Am I developping the UX part correctly ? Meaning am I using the proper widget, is there any better way to do that etc.. I find out about Flutter Performance on Intellj Idea and I saw that most of the pages I developed are red...
FYI : The code I created for a simple page
Flutter inspector result => radio-btn-aligned
import 'package:flutter/material.dart';
import 'package:testapp/my_theme.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: MyAppTheme(ctx: context).defaultTheme,
home: new Scaffold(
appBar: new AppBar(
title: new Text("Title"),
),
body: AddDailyTaskPage()),
);
}
}
enum Options { goal, category }
class AddDailyTaskPage extends StatefulWidget {
#override
_AddDailyTaskPageState createState() => new _AddDailyTaskPageState();
}
class _AddDailyTaskPageState extends State<AddDailyTaskPage> {
Options _options = Options.goal;
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Container(
child: Text("Task Description"),
),
Container(child: Row(
children: [
Expanded(
child: Row(
children: [
Radio<Options>(
value: Options.goal,
groupValue: _options,
onChanged: (Options value) {
setState(() {
_options = value;
});
},
),
Text(
'Goal',
style: new TextStyle(fontSize: 16.0),
)
]
)
),
Expanded(
child: Row(
children: [
Container(
child: Radio(
value: Options.category,
groupValue: _options,
onChanged: (Options value) {
setState(() {
_options = value;
});
},
),
),
Container(
child: Text(
'Category',
style: new TextStyle(
fontSize: 16.0,
),
),
)
],
)
)
],
),)
// Container(
// child: TextField(
// maxLines: 10,
// decoration: InputDecoration(
// // suffixIcon:
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(color: Colors.grey, width: 5.0),
// ),
// enabledBorder: OutlineInputBorder(
// borderSide: BorderSide(color: Colors.black, width: 5.0),
// ),
// hintText: 'Description task',
// ),
// ),
// )
],
),
);
}
}
To see the difference, I checked the sample code provided while creating a flutter Project
FYI :
flutter performance result : auto-increment
As we can see on the previous pic, it doesn't seems optimised.. :/
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Few questions :
1/ Does anyone has / knows a good flutter repo with ton of examples based on performance ?
2/ What is your standard in term of perf ? I mean on my virtual device, the UX seems fluid but if the Flutter Perf is "red", then I'm guessing I'm doing something wrong and there is a better way to do ?
3/ Do you guys knows a website / forum / someone who's willing to do a core review once a week to help me implementing good pattern in my flutter application ?
4/ What is wrong with my current design ? What is wrong with the default design ? Why the performance are doesn't seems good ? I started to read the official documentation for the perf, but how could I know if the UX itself have good perf or not ? Actually by testing some stuff, I find out that putting everything in Container / Row or Column widget, improved a lot the performance but even with this widgets, it's not enough :/
Any advice ?
Thanks for your help
You use a StatefulWidget for the whole page. That means that when you call setState() the whole page gets rebuild.
One example is:
Radio<Options>(
value: Options.goal,
groupValue: _options,
onChanged: (Options value) {
setState(() {
_options = value;
});
},
),
There's no need to rebuild your whole page when you set an option. If you extract that code out into it's own StatefulWidget, only this portion gets rebuild.
You can click on "Track Widget rebuilds" to see what Widgets do rebuild in your app and then think about whether those Widget actually should rebuild.
Once you do smaller Widgets you get the problem that events in one Widget are supposed to influence other Widgets. That's when state management solutions come into play. The weather example of the Bloc package shows a good structure of an app that you can copy.

How to get exact tap position of GestureDetector

GestureDetector always returning same location for any image tapped.
while (i<numImages) {
GestureDetector(
onTap:(){
_onImageTapped(i);
},
child: FadeInImage(
fit: BoxFit.cover,
image: AssetImage(urls[i%5]),
placeholder: AssetImage(urls[i%5]),
)));
images.add(carImage);
i++;
}
}
On card tapped function is as:
_onImageTapped(int position) {
print('$position tapped');
}
You want to use the onTapUp, or onTapDown properties of the GestureDetector, that way you get a TapDownDetails or TapUpDetails etc. which have position details, use as below:
GestureDetector g = new GestureDetector(
onTapDown: (details)
{
print(details.globalPosition);
print(details.localPosition);
},
);
See: https://api.flutter.dev/flutter/gestures/TapUpDetails-class.html
I did
int index=i;
And
_onImageTapped(index);
I got the index of image in which the user tapped.

Flutter white flicker when pushing route before backgroundImage

In my flutter app, after the splash screen animation is finished, it pushes to the HomeRoute.
The HomeRoute has a backgropundImage which is intended to cover the whole screen:
HomeRoute.dart:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/mainBgndsmall.png"),
fit: BoxFit.cover)),
child: SafeArea(child: _buildBody())),
);
}
When the route is pushed, there is a white flicker before the backgroundImage is showed.
Is that a normal behavior or am I doing something wrong when trying to put an image as a background?
Image size is about 500KB or 600KB aprox. PNG image.
The image has not loaded yet that is why the container loads before the image comes up
you can fix it by using a future builder which will display a circular progress indictor until the image is loaded and ready to be rendered
You can use precacheImage in your didChangeDependencies method to increase the chances of your image being loaded prior to the widget being displayed, preventing the white flicker.
#override
void didChangeDependencies() {
super.didChangeDependencies();
precacheImage(const AssetImage("assets/images/mainBgndsmall.png"), context);
}
You may need to convert your widget to a StatefulWidget first in order to pass a BuildContext.
It happens because the image is being loaded.
Alternatively, you can use FutureBuilder Widget to handle images as they load
here example
...
///future type variable to keep value from future method
late Future<String> futureData;
///future method to fetch some data
Future<String> getData(){
///give some duration before return value
await Future.delayed(Duration(seconds: 1));
//some code if you have some code
// ....
///return string
return "oke";
}
#override
didChangeDependencies(){
super.didChangeDependencies();
futureData = getData();
}
#override
Widget build(BuildContext context){
Future.delayed(Duration(seconds: 1));
return Scaffold(
body: FutureBuilder<String>(
future: futureData,
builder:(context, snapshot) {
///if loading is done
if(snapshot.connectionState == ConnectionState.done){
// if future success
if(snapshot.hasData){
///return widget what you want to show
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/mainBgndsmall.png"),
fit: BoxFit.cover)),
child: SafeArea(
child: _buildBody()
)
);
}else{
// if future failed return some widget
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: Text("Image can't load"),
)
);
}
}
///return progress loading
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: CircularProgressIndicator(),
)
);
},
),
);
}
As of now it is considered as flutter framework bug. You can check that here.
Also it is in Github open issue.
You can do one thing, You can use cached_network_image. While loading your image show your own container or whatever you want.

Check image is loaded in Image.network widget in flutter

I am new to Flutter. I try to load network images using image.network widget. it's working fine but sometimes it takes time to load. I added tap listener to image.network during tap I need to check image is fully loaded or not based on the result I need to redirect the page. how to check image is loaded or not?
Code:
new Image.network('http://via.placeholder.com/350x150')
Any help will be appreciated, thank you in advance
You may use the loadingBuilder which is inbuilt feature from flutter for Image.Network
I did it as below:
Image.network(imageURL,fit: BoxFit.cover,
loadingBuilder:(BuildContext context, Widget child,ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null ?
loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
: null,
),
);
},
),
for this kind of issues it's good to use the cached_network_image
so you can provide a placeholder when the image is loading and an error widget in case a resource fails to load
String url = "http://via.placeholder.com/350x150";
CachedNetworkImage(
imageUrl: url,
placeholder: (context,url) => CircularProgressIndicator(),
errorWidget: (context,url,error) => new Icon(Icons.error),
),
for ones who do not need to cache the image can use meet_network_image package,
The package basic usage :
MeetNetworkImage(
imageUrl:
"https://random.dog/3f62f2c1-e0cb-4077-8cd9-1ca76bfe98d5.jpg",
loadingBuilder: (context) => Center(
child: CircularProgressIndicator(),
),
errorBuilder: (context, e) => Center(
child: Text('Error appear!'),
),
)
In addition, you can do that by yourself with using a FutureBuilder,
We need to get data with http call that way, we need to import http before import you also need to add pubspec.yaml and run the command flutter packages get
import 'package:http/http.dart' as http;
FutureBuilder(
// Paste your image URL inside the htt.get method as a parameter
future: http.get(
"https://random.dog/3f62f2c1-e0cb-4077-8cd9-1ca76bfe98d5.jpg"),
builder: (BuildContext context, AsyncSnapshot<http.Response> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start.');
case ConnectionState.active:
case ConnectionState.waiting:
return CircularProgressIndicator();
case ConnectionState.done:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
// when we get the data from the http call, we give the bodyBytes to Image.memory for showing the image
return Image.memory(snapshot.data.bodyBytes);
}
return null; // unreachable
},
);
This way it will start loading, then it will show the loading of the image loading and then the image. Best option if you don't want to use external libs.
Image.network(
imgUrl,
height: 300,
fit: BoxFit.contain,
frameBuilder: (_, image, loadingBuilder, __) {
if (loadingBuilder == null) {
return const SizedBox(
height: 300,
child: Center(child: CircularProgressIndicator()),
);
}
return image;
},
loadingBuilder: (BuildContext context, Widget image, ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) return image;
return SizedBox(
height: 300,
child: Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
: null,
),
),
);
},
errorBuilder: (_, __, ___) => Image.asset(
AppImages.withoutPicture,
height: 300,
fit: BoxFit.fitHeight,
),
)
thank you for your comment thats help to resolve the situation that how to know if the image is loaded or not hope that help
I use a StatefulWidget
need a editing depend on your AffichScreen
situation :
-i have an url that i enter
-if url is correct affich the image if not affich an icon
-if empty affich a Text()
-precacheImage check if the url is correct if not give an error and change _loadingimage(bool) to false to affich the icon eror
-i use a NetworkImage to check with precacheImage and before affich use a Image.network
bool _loadingimage;
ImageProvider _image;
Image _imagescreen;
#override
void initState() {
_loadingimage = true;
_imageUrlfocusNode.addListener(_updateImageUrl);
super.initState();
}
#override
void dispose() {
_imageUrlfocusNode.removeListener(_updateImageUrl);
_quantityfocusNode.dispose();
_imageUrlConroller.dispose();
_imageUrlfocusNode.dispose();
super.dispose();
}
void _updateImageUrl() {
setState(() {
_image = NetworkImage(_imageUrlConroller.text);
});
if (!_imageUrlfocusNode.hasFocus) {
if (_imageUrlConroller.text.isNotEmpty) {
setState(() {
loadimage();
});
}
}
}
void loadimage() {
_loadingimage = true;
precacheImage(_image, context, onError: (e, stackTrace) {
// log.fine('Image ${widget.url} failed to load with error $e.');
print('error $e');
setState(() {
_loadingimage = false;
print(_loadingimage);
});
});
if (_loadingimage == true) {
_imagescreen = Image.network(
_imageUrlConroller.text,
fit: BoxFit.fill,
);
}
}
Container(
width: 100,
height: 100,
margin: EdgeInsets.only(top: 13, right: 11),
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey,
),
),
child:_imageUrlConroller.text.isEmpty
? Text('enter an url')
: !_loadingimage
? Container(
child: Icon(Icons.add_a_photo),
)
: Container(
child: _imagescreen,
),
),

How to Show an Local image till the NetworkImage() Loads Up in flutter?

new CircleAvatar(
backgroundColor: Colors.black87,
backgroundImage: new NetworkImage(url),
radius: 45.0,
)
I Want to show a local image in CircleAvatar until the NetworkImage fully loads from the internet.
You may want to try a FadeInImage wrapped in a ClipOval. FadeInImage provides a placeholder property you can use while the network image is loading.
Note: ClipOval can be expensive if you do it a lot, so use it sparingly.
There is a new official widget for this now!
First, create a folder called assets in the project root directory.
Then, mention the folder in pubspec.yaml file (also found in the project root directory):
flutter:
uses-material-design: true
assets:
- assets/
You can put a picture there, for example, put this as ./assets/loading.gif.
(If you changed files in assets folder, hot reload won't work. Make sure you restart the app entirely.)
Now you can refer to the loading file in the code:
FadeInImage.assetNetwork(
placeholder: 'assets/loading.gif',
image: 'https://github.com/flutter/website/blob/master/src/_includes/code/layout/lakes/images/lake.jpg?raw=true',
);
For more details: https://flutter.io/docs/cookbook/images/fading-in-images#from-asset-bundle
Use a StateflWidget and you can add a listener to the ImageStream and override the initState to trigger a replacement between the local image and the one obtained from the internet when it is fully loaded.
I have used a high resolution image to show the loading time:
var _loadImage = new AssetImage(
'assets/img/basic2-090_loader_loading-512.png');
var _myEarth = new NetworkImage(
"http://qige87.com/data/out/73/wp-image-144183272.png");
bool _checkLoaded = true;
#override
void initState() {
_myEarth.resolve(new ImageConfiguration()).addListener((_, __) {
if (mounted) {
setState(() {
_checkLoaded = false;
});
}
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(child: new Container(
decoration: new BoxDecoration(shape: BoxShape.circle,),
height: 80.0,
width: 80.0,
child: new CircleAvatar(
backgroundColor: Theme
.of(context)
.scaffoldBackgroundColor,
backgroundImage: _checkLoaded ? _loadImage : _myEarth,
),)
)
);
}
}
Two way to solve your problem
1) Using Image.network : If you want to show progressbar,simmer or any other widget when image loading.
Image.network(
"URL",
fit: BoxFit.cover,
loadingBuilder: (BuildContext ctx, Widget child, ImageChunkEvent loadingProgress) {
if (loadingProgress == null) {
return child;
}else {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.green),
),
);
}
},
)
2) Using FadeInImage : If you want to display your local image when network image loading
FadeInImage.assetNetwork(
image:"URL",
placeholder:"assets/loading.png" // your assets image path
fit: BoxFit.cover,
)
You can also use the frameBuilder property. The good thing: you can implement your custom placeholder widget here.
Image.network('https://example.com/my-image',
height: 100,
frameBuilder: (context, child, frame, _) {
if (frame == null) {
// fallback to placeholder
return MyPlaceholderWidget();
}
return child;
}
)
While large images load, show a fallback asset!
new PlutoImage.networkWithPlaceholder("http://68.media.tumblr.com/f7e2e01128ca8eb2b9436aa3eb2a0a33/tumblr_ogwlnpSpcU1sikc68o1_1280.png", new Image.asset("assets/placeholder.png"));
https://github.com/FaisalAbid/pluto
You can Use FadeInImage.
Use a placeholder from asset
FadeInImage.assetNetwork(
placeholder: "assets/images/image1.png",
image:"URL"
),
Use a placeholder from memory
FadeInImage.memoryNetwork(
placeholder: localImageBytes,
image:"URL"
),
I developed a package named flutter_url_image_load_fail to define the loading and failed to load widgets:
LoadImageFromUrl(
'https://upload.wikimedia.org/wikipedia/commons/1/17/Google-flutter-logo.png', //Image URL to load
(image) => image, //What widget returns when the image is loaded successfully
() => Text('Loading...'), //What widget returns when the image is loading
(IRetryLoadImage retryLoadImage, code , message){ //What widget returns when the image failed to load
return RaisedButton(
child: Text('Try Again'),
onPressed: (){
retryLoadImage.retryLoadImage(); //Call this method to retry load the image when it failed to load
},
);
},
requestTimeout: Duration(seconds: 5) //Optionally set the timeout
)
There is a new cached_network_image package that has a "loading" and an "error" images. Along with auto image caching.
https://stackoverflow.com/a/57493334/5502121
You can set as a placeholder anything you want, for example from your assets use Image.asset('assets/images/my_placeholder.png')

Resources