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

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')

Related

Assets do not load but when I hot reload

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.

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.

How to rebuild a particular widget property instead of the whole widget?

I am making an application and for showing circular progress indicator i had used library of modal_progress_hud and when i set the state of inAsyncCall true or false, it rebuild all of its child widgets inside modal_progress_hud. And i do not want to rebuild all the UI again and again. It decreases the efficency of application by increasing usage of GPU. Is there any other way to make it better, that we just change the property and rebuild that property of widget only instead of whole screen and widgets inside it.
bool circularindicator = false;
Color circularColor;
double circularOpacity;
child: ModalProgressHUD(
inAsyncCall: circularindicator,
child: body,
color: circularColor,
opacity: circularOpacity,
),
In body, we have all of the widgets in listview.
And after pressing the login button we called the showProgress() method and set the state and rebuild the widget.
#override
showProgress() {
setState(() {
circularindicator = true;
circularOpacity = 0.5;
circularColor = Colors.grey;
});
}
Make your class StatelessWidget and use Provider Package for state management. Inside the widget build function keep the Provider listener false and wrap the changeable widget with Consumer Widget.
Widget build(BuildContext context) {
final cart = Provider.of<Cart>(context, listen: false);
return GridTileBar(
leading: Consumer<Product>(
builder: (ctx, product, child) => IconButton(
onPressed: () {
product.toggleFavoriteStatus();
},
icon: Icon(product.isFavorite ? Icons.favorite : Icons.favorite_border),
color: Theme.of(context).accentColor,
),
),
trailing: IconButton(
icon: Icon(Icons.shopping_cart),
onPressed: () {
cart.addItem(product.id, product.title, product.price);
},
color: Theme.of(context).accentColor,
),
backgroundColor: Colors.black87,
title: Text(product.title),
);
}
For more details on provider package: State Management Using Provider

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,
),
),

Resources