As humans we are visual creatures. We tend to decipher images quicker than written words. In apps, images get used alot, whether inside a list or standalone. In this article, let's look at some image loading options for flutter.
(a). CachedNetworkImage
A flutter library to show images from the internet and keep them in the cache directory.
How to Install
Run this command:
With Dart:
$ dart pub add cached_network_image
With Flutter:
$ flutter pub add cached_network_image
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get
):
dependencies:
cached_network_image: ^3.0.0
Alternatively, your editor might support dart pub get
or flutter pub get
. Check the docs for your editor to learn more.
Import it
Now in your Dart code, you can use:
import 'package:cached_network_image/cached_network_image.dart';
How to use
The CachedNetworkImage can be used directly or through the ImageProvider. Both the CachedNetworkImage as CachedNetworkImageProvider have minimal support for web. It currently doesn't include caching.
With a placeholder:
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/350x150",
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),
Or with a progress indicator:
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/350x150",
progressIndicatorBuilder: (context, url, downloadProgress) =>
CircularProgressIndicator(value: downloadProgress.progress),
errorWidget: (context, url, error) => Icon(Icons.error),
),
Image(image: CachedNetworkImageProvider(url))
When you want to have both the placeholder functionality and want to get the imageprovider to use in another widget you can provide an imageBuilder:
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/200x150",
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
colorFilter:
ColorFilter.mode(Colors.red, BlendMode.colorBurn)),
),
),
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),
Full Example
Here's a full example of CachedNetworkImage:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'template/globals.dart';
void main() {
runApp(BaseflowPluginExample());
}
/// A Flutter application demonstrating the functionality of this plugin
class BaseflowPluginExample extends StatelessWidget {
/// [MaterialColor] to be used in the app [ThemeData]
final MaterialColor themeMaterialColor =
createMaterialColor(const Color.fromRGBO(48, 49, 60, 1));
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Baseflow $pluginName',
theme: ThemeData(
accentColor: Colors.white60,
backgroundColor: const Color.fromRGBO(48, 49, 60, 0.8),
buttonTheme: ButtonThemeData(
buttonColor: themeMaterialColor.shade500,
disabledColor: themeMaterialColor.withRed(200),
splashColor: themeMaterialColor.shade50,
textTheme: ButtonTextTheme.primary,
),
bottomAppBarColor: const Color.fromRGBO(57, 58, 71, 1),
hintColor: themeMaterialColor.shade500,
primarySwatch: createMaterialColor(const Color.fromRGBO(48, 49, 60, 1)),
textTheme: TextTheme(
bodyText1: TextStyle(
color: Colors.white,
fontSize: 16,
height: 1.3,
),
bodyText2: TextStyle(
color: Colors.white,
fontSize: 18,
height: 1.2,
),
button: TextStyle(color: Colors.white),
headline1: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
visualDensity: VisualDensity.adaptivePlatformDensity,
inputDecorationTheme: const InputDecorationTheme(
fillColor: Color.fromRGBO(37, 37, 37, 1),
filled: true,
),
),
home: AppHome(title: 'Baseflow $pluginName example app'),
);
}
/// Creates a [MaterialColor] based on the supplied [Color]
static MaterialColor createMaterialColor(Color color) {
List strengths = <double>[.05];
Map swatch = <int, Color>{};
final r = color.red, g = color.green, b = color.blue;
for (var i = 1; i < 10; i++) {
strengths.add(0.1 * i);
}
for (var strength in strengths) {
final ds = 0.5 - strength;
swatch[(strength * 1000).round()] = Color.fromRGBO(
r + ((ds < 0 ? r : (255 - r)) * ds).round(),
g + ((ds < 0 ? g : (255 - g)) * ds).round(),
b + ((ds < 0 ? b : (255 - b)) * ds).round(),
1,
);
}
return MaterialColor(color.value, swatch);
}
}
/// A Flutter example demonstrating how the [pluginName] plugin could be used
class AppHome extends StatefulWidget {
/// Constructs the [AppHome] class
AppHome({Key key, this.title}) : super(key: key);
/// The [title] of the application, which is shown in the application's
/// title bar.
final String title;
@override
_AppHomeState createState() => _AppHomeState();
}
class _AppHomeState extends State<AppHome> {
static final PageController _pageController = PageController(initialPage: 0);
int _currentPage = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).bottomAppBarColor,
title: Center(
child: Image.asset(
'res/images/baseflow_logo_def_light-02.png',
width: 140,
),
),
),
backgroundColor: Theme.of(context).backgroundColor,
body: PageView(
controller: _pageController,
children: pages,
onPageChanged: (page) {
setState(() {
_currentPage = page;
});
},
),
bottomNavigationBar: _bottomAppBar(),
);
}
BottomAppBar _bottomAppBar() {
return BottomAppBar(
elevation: 5,
color: Theme.of(context).bottomAppBarColor,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: List.unmodifiable(() sync* {
for (var i = 0; i < pages.length; i++) {
yield Expanded(
child: IconButton(
iconSize: 30,
icon: Icon(icons.elementAt(i)),
color: _bottomAppBarIconColor(i),
onPressed: () => _animateToPage(i),
),
);
}
}()),
),
);
}
void _animateToPage(int page) {
_pageController.animateToPage(page,
duration: const Duration(milliseconds: 200), curve: Curves.linear);
}
Color _bottomAppBarIconColor(int page) {
return _currentPage == page ? Colors.white : Theme.of(context).accentColor;
}
}
Reference
Find complete documentation and example here.
(b). Flutter Advanced Network Image Provider
An advanced image provider that provides caching and retrying for flutter app. It also has zoomable widget and transition to image widget.
Installation
Add this to your pubspec.yaml (or create it):
dependencies:
flutter_advanced_networkimage: any
Then run the flutter tooling:
flutter packages get
Example
Here's ab example:
// using image provider
Image(
image: AdvancedNetworkImage(
url,
header: header,
useDiskCache: true,
cacheRule: CacheRule(maxAge: const Duration(days: 7)),
),
fit: BoxFit.cover,
)
// work with precacheImage
precacheImage(
AdvancedNetworkImage(
url,
header: header,
useDiskCache: true,
cacheRule: CacheRule(maxAge: const Duration(days: 7)),
),
context,
);
// or svg provider (flutter_svg)
SvgPicture(
AdvancedNetworkSvg(url, SvgPicture.svgByteDecoder, useDiskCache: true),
)
// get the disk cache folder size
int cacheSize = await DiskCache().cacheSize();
// clean the disk cache
bool isSucceed = await DiskCache().clear();
// using zooming widget & transitiontoimage widget
ZoomableWidget(
minScale: 0.3,
maxScale: 2.0,
// default factor is 1.0, use 0.0 to disable boundary
panLimit: 0.8,
child: Container(
child: TransitionToImage(
image: AdvancedNetworkImage(url, timeoutDuration: Duration(minutes: 1)),
// This is the default placeholder widget at loading status,
// you can write your own widget with CustomPainter.
placeholder: CircularProgressIndicator(),
// This is default duration
duration: Duration(milliseconds: 300),
),
),
)
// Reload feature included
TransitionToImage(
image: AdvancedNetworkImage(url,
loadedCallback: () {
print('It works!');
},
loadFailedCallback: () {
print('Oh, no!');
},
loadingProgress: (double progress) {
print('Now Loading: $progress');
},
),
loadingWidgetBuilder: (_, double progress, __) => Text(progress.toString()),
fit: BoxFit.contain,
placeholder: const Icon(Icons.refresh),
width: 400.0,
height: 300.0,
enableRefresh: true,
);
// Scale the widget size. (Origin point was fixed to screen's center)
ZoomableWidget(
panLimit: 1.0,
maxScale: 2.0,
minScale: 0.5,
singleFingerPan: true,
multiFingersPan: false,
enableRotate: true,
child: Image(
image: AssetImage('graphics/background.png'),
),
zoomSteps: 3,
),
Reference
Find example here folder.