Cached Network SVG Image - flutter

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

Related

Exception Flutter from fetch network Image without connection internet

after turning off the internet i gets this error: "Remove network images from cache on any exception during loading"
my app fetch pictures from api. how can i fix this bug how i prevent that?
return Column(children: [
GestureDetector(
child: Image.network(thumbnailUrl))])
You can use the Cached Network Image Plugin if you are developing for android and ios. In Web, the plugin is not working as expected.
Use the following as a widget for your application.
import 'package:cached_network_image/cached_network_image.dart';
Widget commonCacheImageWidget(String? url, {double? width, BoxFit? fit, double? height}) {
if (url!.startsWith('http')) {
return CachedNetworkImage(
placeholder: (context, url) => Image.asset('assets/path....', fit: BoxFit.cover),
imageUrl: url,
height: height,
width: width,
fit: fit,
);
} else {
return Image.asset(url, height: height, width: width, fit: fit);
}
}
In Placeholder you can have any widget, here am using a local image that is stored as an asset.
Or You can check whether the internet connection is there or not before loading the image and change that to some other widget.

Select source image resolution dynamically

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

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 do you use SVG's on Flutter Web?

The flutter_web docos say to that dart:svg is ported, but how do you use that with the flutter asset / widget system?
Honestly the best solution I've found is to load the image over a network for the web. Store the asset on a CDN somewhere, get it from the CDN on the web version, and retrieve it from your assets locally on iOS/Android.
I've created a CrossPlatformSvg widget using this library: https://pub.dev/packages/flutter_svg, something like:
class CrossPlatformSvg {
static Widget asset(
String assetPath, {
double width,
double height,
BoxFit fit = BoxFit.contain,
Color color,
alignment = Alignment.center,
String semanticsLabel,
}) {
// `kIsWeb` is a special Flutter variable that just exists
// Returns true if we're on web, false for mobile
if (kIsWeb) {
return Image.network(
assetPath,
width: width,
height: height,
fit: fit,
color: color,
alignment: alignment,
);
} else {
return SvgPicture.network(
assetPath,
width: width,
height: height,
fit: fit,
color: color,
alignment: alignment,
placeholderBuilder: (_) => Container(
width: 30,
height: 30,
padding: EdgeInsets.all(30),
child: CircularIndicator(),
),
);
}
}
}
#aterenshkov's approach worked for me (see comments under Jack's answer). Here are the details to implement...
iOS / Android
child: SvgPicture.asset('assets/yourimage.svg')
Web
// remove assets folder reference
child: SvgPicture.asset('yourimage.svg')
Combine these 2 together...
import 'package:flutter/foundation.dart'; // provides kIsWeb property
...
child: kIsWeb ? SvgPicture.asset('yourimage.svg') : SvgPicture.asset('assets/yourimage.svg')
My Flutter web app would render SVGs in a desktop web browser but not a mobile web browser using flutter_svg. I found it necessary to build with canvaskit support in order for SVGs to render on mobile:
flutter build web --web-renderer canvaskit
However, the docs state that canvaskit adds about 2MB in download size, which was a dealbreaker for me. Sad to say, but I will be using raster images until this is resolved.
flutter_svg version 1.0.0 is out since Dec 2, 2021 including web support. So there is no longer a blocker to use svg images inside a Flutter project.
#RumbleFish has nicely but using ternary operation at many can make the code messy.
My approach to this is:
Create an Extension Function on String to replace assets/ from the path.
extension ForWeb on String {
String forWeb({required bool web}) => web ? this.replaceFirst('assets/','') : this;
}
Now in code:
SvgPicture.asset("assets/images/logo.png".forWeb(web: kIsWeb));

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.