Flutter - Display Blurhash Image Placeholder Examples

How to use BlurHash as an image placeholder in Flutter? Find out in this tutorial.

Loading an image from the network may take a few seconds to complete, depending on the connection speed. While the image is being fetched, it's quite common to show a placeholder. There are some techniques for showing a placeholder. For example, you can show a colored box. However, it would be nicer if the placeholder can be similar to the actual image. For that purpose, you can use BlurHash.

BlurHash is a compact representation of a placeholder for an image. It works by generating a hash string from an image. The generated hash string will be used to render the placeholder. This tutorial shows how to decode the BlurHash string to be rendered as an image placeholder in a Flutter application.

Using flutter_blurhash Package

The Flutter Community has created a package called flutter_blurhash which makes it easier for us to render a placeholder based on the given hash string.

Add Dependency

To use the flutter_blurhash, you need to add it as a dependency in the dependencies section of pubspec.yaml file. This tutorial uses version 0.6.0 of the package.

  dependencies:
    flutter_blurhash: ^0.6.0

Then, run flutter pub get to install the package.

Display Blurhash Image

To use the package, you need to add the below import statement.

  import 'package:flutter_blurhash/flutter_blurhash.dart';

After that, you can call the constructor.

  const BlurHash({
    required String hash,
    Key? key,
    Color color = Colors.blueGrey,
    BoxFit imageFit = BoxFit.fill,
    double decodingWidth = _DEFAULT_SIZE,
    double decodingHeight = _DEFAULT_SIZE,
    String image,
    VoidCallback? onDecoded,
    VoidCallback? onReady,
    VoidCallback? onStarted,
    Duration duration = const Duration(milliseconds: 1000),
    Curve curve = Curves.easeOut,
  })

The constructor requires you to pass a parameter hash which is the hash string computed using the BlurHash algorithm. If you don't already have the hash string, you can use their official website blurha.sh to generate the hash string from the image that you want to use.

Below is an example which only passes the hash argument. Because the Image argument is not passed, it will show the placeholder forever.

  const BlurHash(
    hash: 'LsG*BvEeM{n#-tR%W9oI5Tw[xCay',
  ),

Output:

Flutter - BlurHash

Next is another example where the image argument is passed with a remote URL of an image as the value.

  const BlurHash(
    hash: 'LsG*BvEeM{n#-tR%W9oI5Tw[xCay',
    image: 'https://www.psdstack.com/wp-content/uploads/2019/08/copyright-free-images-750x420.jpg',
  ),

Output:

Flutter - BlurHash

Set Size

In most cases, you also need to set the size of the area where the placeholder is rendered (which will be occupied by the image after it has been loaded). The easiest way to set the size is by wrapping the BlurHash widget as the child of another widget with size constraints. For example, you can set the BlurHash widget as the child of a SizedBox widget.

  const SizedBox(
    width: 200,
    height: 200,
    child: const BlurHash(
      hash: 'LsG*BvEeM{n#-tR%W9oI5Tw[xCay',
      image: 'https://www.psdstack.com/wp-content/uploads/2019/08/copyright-free-images-750x420.jpg',
    ),
  )

Output:

Flutter - BlurHash - Size

Set Image Fit

You can set how to fit the image to the available space by passing a BoxFit enum as the imageFit argument to the constructor. If you don't pass the argument, the value defaults to BoxFit.fill. The usage of imageFit argument is similar to the fit property of FittedBox. You can read our tutorial about FittedBox which shows the differences between the BoxFit enums.

The below example sets the imageFit to BoxFit.fitWidth

  const SizedBox(
    width: 200,
    height: 200,
    imageFit: BoxFit.fitWidth,
    child: const BlurHash(
      hash: 'LsG*BvEeM{n#-tR%W9oI5Tw[xCay',
      image: 'https://www.psdstack.com/wp-content/uploads/2019/08/copyright-free-images-750x420.jpg',
    ),
  )

Output:

Flutter - BlurHash - Image Fit - BoxFit.fixWidth

The above screenshot shows the output when the image has been loaded. As you can see, if the image doesn't fill the entire box, a portion of the placeholder is still visible. You may need a workaround to handle that problem. But if you know the size or the aspect ratio from the beginning, you can adjust the size of the widget by applying size constraints (usually by using Container, SizedBox, BoxConstraints, etc.) or set the aspect ratio using AspectRatio widget.

Set Animation Duration

After the image has been successfully downloaded, the image will be animated for a given duration before completely shown. The duration can be set by passing a Duration value as the duration argument. The default value if you don't pass the argument is 1 second.

  const SizedBox(
    width: 200,
    height: 200,
    duration: const Duration(seconds: 3),
    child: const BlurHash(
      hash: 'LsG*BvEeM{n#-tR%W9oI5Tw[xCay',
      image: 'https://www.psdstack.com/wp-content/uploads/2019/08/copyright-free-images-750x420.jpg',
    ),
  )

Output:

Flutter - BlurHash - Animation Duration

Set Animation Curve

The animation curve can be set by passing curve argument. The default value is Curves.easeOut.

  const SizedBox(
    width: 200,
    height: 200,
    curve: Curves.bounceInOut,
    child: const BlurHash(
      hash: 'LsG*BvEeM{n#-tR%W9oI5Tw[xCay',
      image: 'https://www.psdstack.com/wp-content/uploads/2019/08/copyright-free-images-750x420.jpg',
    ),
  )

Output:

Flutter - BlurHash - Animation Curve - bounceInOut

Add Callback Functions

There are some callback functions you can pass to the constructor.

  • onDecoded: Called when the hash is decoded.
  • onStarted: Called when the download starts.
  • onReady: Called when the image is downloaded.

All of them are VoidCallback, which has no arguments and returns no data. Below is the example of how to pass the callback functions.

  BlurHash(
    hash: 'LsG*BvEeM{n#-tR%W9oI5Tw[xCay',
    image: 'https://www.psdstack.com/wp-content/uploads/2019/08/copyright-free-images-750x420.jpg',
    onStarted: () {
      print('onStarted');
    },
    onDecoded: () {
      print('onDecoded');
    },
    onReady: () {
      print('onReady');
    },
  )

BlurHash - Parameters

  • Key? key: The widget's key.
  • required String hash: The hash to decode.
  • color: Displayed background color before decoding. Defaults to Colors.blueGrey.
  • imageFit: How to fit the decoded hash and the downloaded image. Defaults to BoxFit.fill.
  • double decodingWidth: Decoding definition. Defaults to 32.
  • double decodingHeight: Decoding definition. Defaults to 32.
  • String image: Remote resource to download.
  • VoidCallback? onDecoded: A callback to be called when the hash is decoded.
  • VoidCallback? onReady: A callback to be called when the hash is downloaded.
  • VoidCallback? onStarted: A callback to be called when the download starts.
  • Duration duration: The animation duration. Defaults to const Duration(milliseconds: 1000).
  • Curve curve: The animation curve. Defaults to Curves.easeOut.

Full Code

  import 'package:flutter/material.dart';
  import 'package:flutter_blurhash/flutter_blurhash.dart';
  
  void main() => runApp(MyApp());
  
  class MyApp extends StatelessWidget {
  
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Woolha.com Flutter Tutorial',
        home: BlurHashExample(),
      );
    }
  }
  
  class BlurHashExample extends StatelessWidget {
  
    @override
    Widget build(BuildContext context) => MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text("BlurHash")),
        body: Center(
          child: SizedBox(
            width: 200,
            height: 200,
            child: BlurHash(
              imageFit: BoxFit.fitWidth,
              duration: const Duration(seconds: 3),
              curve: Curves.bounceInOut,
              hash: 'LsG*BvEeM{n#-tR%W9oI5Tw[xCay',
              image: 'https://www.psdstack.com/wp-content/uploads/2019/08/copyright-free-images-750x420.jpg',
              onStarted: () {
                print('onStarted');
              },
              onDecoded: () {
                print('onDecoded');
              },
              onReady: () {
                print('onReady');
              },
            ),
          ),
        ),
      ),
    );
  }

Summary

That's how to decode a BlurHash-encoded value to be displayed as an image placeholder. It can be done easily thanks to flutter_blurhash package.