Select source image resolution dynamically - flutter

I'm building an app where the same image can be displayed in a lot of different sizes (big on desktop/tablet and smaller on phones). I also want to take into account the device pixel density to always load the most appropriate source.
I know this is possible in HTML using the srcset and sizes attributes to specify sources and sizes but how would I do something similar in Flutter?

Try AspectRatio, this is responsive for all sizes
AspectRatio(
aspectRatio: 4 / 3, //change value here
child: new Container(
color: Colors.red,
),
),

You can get the display size of the image at the time of build using a LayoutBuilder and the device pixel density using MediaQueries.
I created a package that does just that : https://pub.dev/packages/responsive_image
Just specify your sources and the widget will take care of selecting the most appropriate source and render the image.
ResponsiveImage(
srcSet: {
64: "https://via.placeholder.com/64",
128: "https://via.placeholder.com/128",
256: "https://via.placeholder.com/256",
512: "https://via.placeholder.com/512",
},
scalePreference: ScalePreference.Upper,
);
You can also use the builder to further customize the display of the image (for example using cached_network_image)
ResponsiveImage(
srcSet: {
256: "https://via.placeholder.com/256",
512: "https://via.placeholder.com/512",
1024: "https://via.placeholder.com/1024",
},
builder: (BuildContext context, String url) {
return CachedNetworkImage(
imageUrl: url,
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
);
},
);

Related

Cached Network SVG Image

I want to display an SVG picture retrieved from network with the help of Flutter_SVG package and use the same picture in different pages with the Hero widget. But each time I use SvgPicture.network() widget, it loads the image again and again from network;
Page 1 & Page 2
Hero(
tag: 'randomTag',
child: SvgPicture.network(url),
),
I have tried to combine Cached Network Image dependency with Flutter_SVG package but don't know how to use them as a widget together;
Hero(
tag: 'randomTag',
child: CachedNetworkImage(
imageUrl: url,
imageBuilder: (context, ImageProvider<Object> imageProvider) {
// How to use ImageProvider<Object> with SvgPicture?
}
),
),
svg_cached_network_image dependency is not an option since it is not compatible with other dependencies that I use.
Use flutter_cache_manager to save svg from internet
This line get svg from internet and save it to local, and next time you call it it will get from local
var file = await DefaultCacheManager().getSingleFile(url);
https://pub.dev/documentation/flutter_cache_manager/latest/flutter_cache_manager/BaseCacheManager/getSingleFile.html

FutureBuilder with Icon placeholder flickers

I'm using a FutureBuilder to load album thumbnails into a ListTile, as follows:
ListTile _albumTile(Album album, BuildContext context) {
return ListTile(
leading: FutureBuilder<Uint8List>(
future: AndroidContentResolver.instance.loadThumbnail(
uri: album.thumbnailUri,
width: 56,
height: 56,
),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Image.memory(snapshot.data!);
} else {
return const FittedBox(
fit: BoxFit.contain, child: Icon(Icons.album, size: 56));
}
}),
title: Text(album.album),
subtitle: Text(album.artist),
);
}
But, as the image loads, the placeholder icon is replaced with a blank image, and then with the final thumbnail. The blank image has the wrong width, which results in the ListTile title and subtitle jumping around, causing a flicker.
The following sequence of screenshots shows three consecutive frames:
Image placeholders.
Some of the futures have completed, and are showing thumbnails. The other tiles have a blank image (and the text jumps to the left).
All of the futures have completed.
Even when I fix the text jumping around -- by specifying fit: BoxFit.contain, width: 56, height: 56 for the image -- I still get a flash of white before the thumbnail appears.
What am I doing wrong?
Use precacheImage function to prefetch an image into the image cache.
If the image is later used by an Image or BoxDecoration or FadeInImage, it will probably be loaded faster.
I solved it by using frameBuilder. The documentation says:
If this is null, this widget will display an image that is painted as soon as the first image frame is available (and will appear to "pop" in if it becomes available asynchronously).
This describes exactly what I'm seeing.
It continues with the following:
Callers might use this builder to add effects to the image (such as fading the image in when it becomes available) or to display a placeholder widget while the image is loading.
...and the attached example shows how to implement a fade-in effect. For simplicity, however, I opted for the following:
return Image.memory(
snapshot.data!,
frameBuilder: (context, child, frame, wsl) {
if (frame != null) {
return child;
} else {
return _albumThumbnailPlaceholder();
}
},
Widget _albumThumbnailPlaceholder() {
return FittedBox(fit: BoxFit.contain, child: Icon(Icons.album, size: 56));
}
This seems to completely get rid of the blank frame.

Application crashes when using CachedNetworkImage

Application crashes when using CachedNetworkImage in listview. If there are a lot of pictures, then the application freezes and crashes. Is it possible to load each image one by one, asynchronously? Can I have a code example? Thanks.
And so, if you have the same problem as me, and you have a large list of pictures, then you can do the following:
1.Enable ListView pagination. So that when scrolling, not the entire ListView is loaded, but for example only 10 items from the List.
2.Compress pictures to the desired size using the following parameters:
memCacheWidth, memCacheHeight, maxHeightDiskCache, maxWidthDiskCache
Here is my example:
CachedNetworkImage(
memCacheWidth: 45,
memCacheHeight: 60,
maxHeightDiskCache: 60,
maxWidthDiskCache: 45,
imageUrl: imageUrl,
imageBuilder: (context, imageProvider) => imageBuilderWidget(imageProvider),
placeholder: (context, url) => placeholderWidget(),
errorWidget: (context, url, error) => errorWidget(),
);
After adding these options, remove app from the emulator and do a flutter clean
if need to cache images Use Opt imised cached image package. I had the same issue this package solved. if not working change width of images, add pagination if possible
You can use Image.network, it solved my crash issue on IOS.
Image.network('https://example.com/image.jpg',
errorBuilder: (context, error, stackTrace) {
print(error); //do something
},
loadingBuilder: (context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
},
),

Flutter : set default image in Image.file

I'm currently creating Updating Image process in Flutter app.
I already succeed getting image that pass from some widget defined in View.dart to UpdateScreen widget defined in Update_screen.dart by using Network Image.
CircleAvatar(
radius: 100,
backgroundImage: NetworkImage(
'${Urls.BASE_API_IMAGE}/${widget.imageUpdate}'),
),
My question is, how to set default image using Image.file() ? , because I must use Image.file() for updating data.
Thank's
My full source code :
My Full Source Code Here
you can use this package cached_network_image as it makes it simple to set a default image.
Example
CachedNetworkImage(
imageUrl: "your url",
placeholder: (context, url) =>Your default Image Widget(),
errorWidget: (context, url, error) => new Icon(Icons.error),
),

How to fix Listview scrolling jank when loading images from network

I am loading images using Image.network for each item in a list using the following code:
Image getEventImageWidget(AustinFeedsMeEvent event) {
return event.photoUrl.isNotEmpty ?
Image.network(
event.photoUrl,
width: 77.0,
height: 77.0,
) : Image.asset(
'assets/ic_logo.png',
width: 77.0,
height: 77.0,
);
}
When I scroll up and down, the list sometimes hangs when loading the images. Is there a way I can load the images on a background thread? What can I do to help fix scrolling performance?
NOTE: When I looked back at this, I found that the images that I was using were really large.
There are two was to speed up the rendering of your ListView of images.
The first is to set the cacheExtent property to a larger value in your ListView constructor. This property controls how much offscreen widgets are rendered, and will help by causing the rendering to start a bit sooner.
The second is to pre-cache your images using precacheImage. Flutter has an in-memory cache, so it is generally to necessary to cache everything to disk to get good read performance. Instead, you can ask Flutter to download these images ahead of time so that they are ready when the widget is built. For example, if you have a list of urls of your image, then in an initState method you could ask Flutter to cache all of them.
final List<String> imageUrls = [ /* ... */ ];
#override
void initState() {
for (String url in imageUrls) {
precacheImage(new NetworkImage(url), context);
}
super.initState();
}
Are you sure your images are not very heavy? Check the size of the images first.
Also you can use the package named: cache_network_image
It's very simple :
new Image(image: new CachedNetworkImageProvider(url))
UPDATE (Package was updated)
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/350x150",
placeholder: (context, url) => new CircularProgressIndicator(),
errorWidget: (context, url, error) => new Icon(Icons.error),
),
you can also use:
FadeInImage.assetNetwork(
placeholder: 'assets/ic_logo.png',
image: event.photoUrl,
height: 77.0,
width: 77.0,
fit: BoxFit.cover,
fadeInDuration: new Duration(milliseconds: 100),
),
but yeah, per diegoveloper, you sure your images aren't huge? Listview has no problem rendering anything that's close to reasonable in size.
You can create a Stateful Widget that creates the ListView with placeholder images, then have it have an async method you call after build() that loads the images from network (one by one) and then changes the state of the previously mentioned widget to replace the placeholder with the correct image. As a bonus, you can create a cache that stores the images so they don't have to be downloaded each time the ListView enters scope (here you would have the async method look in the cache for the image and if it doesn't find it there, download it).
As a side note, this would obviously require giving each of the images in the ListView an index.