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:

Lottie Animations in flutter app - lottiefiles

Lottie Animations in flutter app - ...
Lottie Animations in flutter app - lottiefiles
 $ 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.