Flutter FadeInImage for Networking Image | Lazy Image Loading

We will see an example how to lazy load images using FadeInImage Widget Flutter. Previously we have seen how to use caching for image loading in Flutter using cached_network_image plugin. 

We will also see how to use BoxDecoration to style FadeInImage widget.

But that's a plugin, not part of the Flutter core Framework. On the other FadeInImage is part of Flutter core framework.

If we use FadeInImage widget, we would be able to use image placeholder just like the plugin.


class CustomImage extends StatelessWidget {
  final String image;
  final double height;
  final double width;
  final BoxFit fit;
  final String placeholder;

  CustomImage(
      {required this.image, required this.height, required this.width, required this.fit, required this.placeholder});

  @override
  Widget build(BuildContext context) {
    return FadeInImage.assetNetwork(
      placeholder: "assets/img.png",
      height: height,
      width: width,
      fit: fit,
      image: image,
      imageErrorBuilder: (c, o, s) =>
          Image.asset(
            placeholder,
            height: height, width: width, fit: fit,
          ),
    );
  }
}

placeholder: during network image loading shows the asset image. This image should be in your asset folder. it means this image in this placeholder would be shown until the network image has been loaded completely.

imageErrorBuilder: if the network image cannot be loaded for some reasons you can need to use a fallback image. This image should be in your asset folder.

Complete code FadeInImage

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home:  CustomImage(image:
          "http://mvs.bslmeiyu.com/storage/profile/2022-05-13-627e303a38f63.png"
          , height: 200, width: 200, fit: BoxFit.cover, placeholder: "assets/img.png")
    );
  }
}

class CustomImage extends StatelessWidget {
  final String image;
  final double height;
  final double width;
  final BoxFit fit;
  final String placeholder;

  CustomImage(
      {required this.image, required this.height, required this.width, required this.fit, required this.placeholder});

  @override
  Widget build(BuildContext context) {
    return FadeInImage.assetNetwork(
      placeholder: "assets/img.png",
      height: height,
      width: width,
      fit: fit,
      image: image,
      imageErrorBuilder: (c, o, s) =>
          Image.asset(
            placeholder,
            height: height, width: width, fit: fit,
          ),
    );
  }
}

FadeInImage more tips

You will see that, with the current code, there is black screen time. When placeholder image on the screen changed by network image, there is a black screen.

You can overcome this problem using fade in and fade out duration time control.

fadeInDuration: Duration(milliseconds: 5),
fadeOutDuration: Duration(milliseconds: 5)

Put the above code inside FadeInImage.assetNetwork

Styling FadeInImage with BoxDecoration

If you want to style FadeInImage, you can not use FadeInImage.assetNetwork. We will just use FadeInImage inside a Container(). 

With the Container(), you can style using BoxDecoration. We know that BoxDecoration takes DecorationImage. For DecorationImage property, we will provide FadeInImage. 

And at the same time we will use AssetImage() for the placeholder and NetworkImage() for the image

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Scaffold(
          body: Container(
            height: 500,
            width: 300,
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(20),

                image: DecorationImage(
                  image: FadeInImage(
                    placeholder: AssetImage("assets/holder.png"),
                    fit: BoxFit.cover,
                    image:NetworkImage("http://mvs.bslmeiyu.com/storage/profile/2022-05-13-627e303a38f63.png",),
                    fadeInDuration: const Duration(milliseconds: 5),
                    fadeOutDuration: const Duration(milliseconds: 5),
                    imageErrorBuilder: (c, o, s) => Image.asset(
                      "assets/error.png",
                      height: 200,
                      width: 200,
                      fit: BoxFit.cover,
                    ),
                  ).image,
                  fit: BoxFit.cover
                )
            ),

          ),
        ));
  }
}

You also see that, we are using .image to return an ImageProvider to the image property of DecorationImage.

You can play with the below properties

  FadeInImage.assetNetwork({
    Key? key,
    required String placeholder,
    this.placeholderErrorBuilder,
    required String image,
    this.imageErrorBuilder,
    AssetBundle? bundle,
    double? placeholderScale,
    double imageScale = 1.0,
    this.excludeFromSemantics = false,
    this.imageSemanticLabel,
    this.fadeOutDuration = const Duration(milliseconds: 300),
    this.fadeOutCurve = Curves.easeOut,
    this.fadeInDuration = const Duration(milliseconds: 700),
    this.fadeInCurve = Curves.easeIn,
    this.width,
    this.height,
    this.fit,
    this.placeholderFit,
    this.alignment = Alignment.center,
    this.repeat = ImageRepeat.noRepeat,
    this.matchTextDirection = false,
    int? placeholderCacheWidth,
    int? placeholderCacheHeight,
    int? imageCacheWidth,
    int? imageCacheHeight,
  })

Recent posts