surga Lab

開発したい!!

Flutter 画像ロード時にプレースホルダーを表示する

Flutterアプリで画像を表示する際にロード画面を表示する方法です。

画像の表示 with ロード画面

Flutterアプリで画像を表示する方法は以前のブログで紹介しましたが、
インターネットの画像を表示する場合、少なからずダウンロードの時間が発生します。

ユーザーからすると画面にいきなり画像が表示されるので、あまりよろしくありません。

それを解決するために、画像のダウンロード中はローディングを表示(PlaceHolder)して、
ユーザーへ「今はロード中ですよ、ちょっと待ってね」と伝えることにしましょう。

FadeInImageを使う

FadeInImageを使えば簡単に実装することができます。

FadeInImage.assetNetwork(
  placeholder: 'images/loading.gif',
  image: 'https://foo.png',
);

placeholderにはassetsの画像を指定します。
gif画像も可能ですので、ローディングgif画像なら「動いている感」をユーザーに与えられますね。

imageにはダウンロード先のURLを指定します。

FadeInImageにはassetNetworkmemoryNetworkの関数があり、memoryの場合はUint8Listで指定します。

f:id:hisurga:20190619001246g:plain

コード全体

import 'package:flutter/material.dart';

class MyImageFadeinPage extends StatefulWidget {
  MyImageFadeinPage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyImageFadeinPageState createState() => _MyImageFadeinPageState();
}

class _MyImageFadeinPageState extends State<MyImageFadeinPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(children: <Widget>[
        Container(
          child: FadeInImage.assetNetwork(
            height: 400,
            placeholder: 'images/loading.gif',
            image:
                'https://cdn-ak.f.st-hatena.com/images/fotolife/h/hisurga/20190616/20190616231036.png',
          ),
        ),
        Center(
          child: Text('Bottom Text'),
        ),
      ]),
    );
  }
}

CachedNetworkImageを使う

FadeInImageは便利ですが、ローディングはassetやmemoryで用意しなければいけません。

CachedNetworkImageならplaceholderにウィジェットを配置することができます。

cached_network_image | Flutter Package

さらには、失敗時画面の用意もキャッシュの利用も簡単にできます。
(あえてキャッシュを利用したくない場合のオプションは用意されていないようです)

外部プラグインですが、公式のcookbookでも紹介されています。

pubspec.yamlの編集

pubspec.yamlにcached_network_imageを追加します。

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.2
  cached_network_image: "^0.4.0"

placeholderとerrorWidgetの配置

placeholdererrorWidgetにはウィジェットを配置できるので、CircularProgressIndicatorやTextなどを配置することができます。

CachedNetworkImage(
        imageUrl: "http://foo.png",
        placeholder: CircularProgressIndicator(),
        errorWidget: Icon(Icons.error),
     ),

ダウンロード成功時

f:id:hisurga:20190619003338g:plain

失敗時

f:id:hisurga:20190619003440g:plain

コード全体

import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';

class MyImageCachednetworkPage extends StatefulWidget {
  MyImageCachednetworkPage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyImageCachednetworkPageState createState() =>
      _MyImageCachednetworkPageState();
}

class _MyImageCachednetworkPageState extends State<MyImageCachednetworkPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(children: <Widget>[
        Container(
          height: 400,
          child: CachedNetworkImage(
            imageUrl:
                "https://cdn-ak.f.st-hatena.com/images/fotolife/h/hisurga/20190616/20190616231036.png",
            placeholder: Center(
              child: CircularProgressIndicator(),
            ),
            errorWidget: Center(
              child: Icon(Icons.error),
            ),
          ),
        ),
        Center(
          child: Text('Bottom Text'),
        ),
      ]),
    );
  }
}

プロジェクトの全体像はGitHubに載せています。

github.com

参考にさせていただいたサイト

Fade in images with a placeholder - Flutter

FadeInImage class - widgets library - Dart API

Work with cached images - Flutter

cached_network_image | Flutter Package