PR

[Flutter]Flutter Widget of the Week「#13 FadeInImage」、「#14 StreamBuilder」

Flutter

はじめに

前回はFlutter Widget of the Weekの「#11 SliverAppBar」、「#12 SliverList & SliverGrid」を紹介しました。

今回はその続きで「#13 FadeInImage」、「#14 StreamBuilder」の2つです。

前回の記事はこちら

Flutter Widget of the Week

環境

  • Flutter 2.8.1

記事にした時点でのバージョンです。GitHubに公開しているのは常に最新の安定版(stable)を使う予定です。

#13 FadeInImage

FadeInImageとは

画像をURLからダウンロードして表示する際に、ダウンロードが終わるまでの間プレースホルダとして何かしらの画像を表示したい場合に、このFadeInImageのウィジェットを使います。

サンプルコード

import 'package:flutter/material.dart';

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

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('FadeInImage'),
),
body: SafeArea(
child: Center(
child: FadeInImage.assetNetwork(
placeholder: 'assets/sample.png',
image:
'https://upload.wikimedia.org/wikipedia/commons/thumb/4/44/Google-flutter-logo.svg/440px-Google-flutter-logo.svg.png',
height: 50,
),
),
),
);
}
}

結果

初期状態ではアプリ内の画像が表示されていますが、

通信が終了するとアプリ内の画像がフェード・アウトし、URLの画像がフェードインしてきました。

動画

公式リファレンス

FadeInImage class - widgets library - Dart API
API docs for the FadeInImage class from the widgets library, for the Dart programming language.

#14 StreamBuilder

StreamBuilderとは

非同期のデータストリームをウィジェットで使いたい場合にこのStreamBuilderを使います。

データストリームに変更があった場合に、StreamBuilder内のbuilder内を再ビルドしてくれます。

StreamBuilderを使う場合は、データの存在を確認できるhasDataや、エラーがあるかどうかのhasErrorは実装しておいたほうが良いです。

サンプルコード

import 'package:flutter/material.dart';

class SamplePage014 extends StatefulWidget {
  const SamplePage014({
    Key? key,
  }) : super(key: key);

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

class _SamplePage014State extends State<SamplePage014> {
  final Stream<String> _successStream = (() async* {
    await Future<void>.delayed(const Duration(seconds: 1));
    yield 'Success';
    await Future<void>.delayed(const Duration(seconds: 1));
  })();

  final Stream<String> _errorStream = (() async* {
    await Future<void>.delayed(const Duration(seconds: 1));
    throw Exception('Error');
    yield 'Success';
    await Future<void>.delayed(const Duration(seconds: 1));
  })();

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('#14 StreamBuilder'),
      ),
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              const Text('StreamBuilder Success'),
              StreamBuilder<String>(
                stream: _successStream,
                builder: (context, snapshot) {
                  return Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      _samplePage014StreamWidget(snapshot),
                      _samplePage014StreamStateWidget(snapshot),
                    ],
                  );
                },
              ),
              const SizedBox(height: 20),
              const Text('StreamBuilder Error'),
              StreamBuilder<String>(
                stream: _errorStream,
                builder: (context, snapshot) {
                  return Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      _samplePage014StreamWidget(snapshot),
                      _samplePage014StreamStateWidget(snapshot),
                    ],
                  );
                },
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _samplePage014StreamWidget(AsyncSnapshot<String> snapshot) {
    if (snapshot.hasError) {
      return Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Icon(
            Icons.error,
            color: Colors.red,
          ),
          Text(snapshot.error?.toString() ?? ''),
        ],
      );
    }
    if (!snapshot.hasData) {
      return const CircularProgressIndicator();
    }
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        const Icon(
          Icons.check_circle,
          color: Colors.green,
        ),
        Text(snapshot.data ?? ''),
      ],
    );
  }

  Widget _samplePage014StreamStateWidget(AsyncSnapshot<String> snapshot) {
    var text = '';
    switch (snapshot.connectionState) {
      case ConnectionState.waiting:
        text = 'waiting';
        break;
      case ConnectionState.none:
        text = 'none';
        break;
      case ConnectionState.active:
        text = 'active';
        break;
      case ConnectionState.done:
        text = 'done';
        break;
    }
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        const Icon(
          Icons.info,
          color: Colors.blue,
        ),
        Text('status : $text'),
      ],
    );
  }
}

結果

最初はSuccess、Error両方とも読込中ですが

読み込みが完了するとSuccessとErrorに表示が切り替わりますが、Successは処理が終わっていないのでステータスがactiveのままです。

Successの処理が完了しました。

動画

公式リファレンス

StreamBuilder class - widgets library - Dart API
API docs for the StreamBuilder class from the widgets library, for the Dart programming language.

さいごに

FadeInImageは使い所がよくわからん。。。

おすすめ参考書

リンク

GitHub - nobushiueshi/flutter_widget_of_the_week
Contribute to nobushiueshi/flutter_widget_of_the_week development by creating an account on GitHub.

コメント

タイトルとURLをコピーしました