PR

[Flutter]Flutter Widget of the Week「#6 FutureBuilder」、「#7 FadeTransition」、「#8 FloatingActionButton」

Flutter

はじめに

前回はFlutter Widget of the Week#3 Wrap」、「#4 AnimatedContainer」、「#5 Opacity」を紹介しました。

今回はその続きで「#6 FutureBuilder」、「#7 FadeTransition」、「#8 FloatingActionButton」の3つです。

前回の記事はこちら

Flutter Widget of the Week

環境

  • Flutter 2.8.0

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

#6 FutureBuilder

FutureBuilderとは

DartFutureを使うことにより非同期処理が行なえます。

ウィジェット上でそんな非同期処理を使いたい場合はFutureBuilderを使います。

使い方は非同期処理をfutureに設定し、builderに表示したいウィジェットを設定します。

ConnectionStatefutureの状況を確認し、futureビジーな場合は読み込み中等のウィジェットを表示します。

処理が終わった際はエラーが起きていないかを確認したほうがよいそうです。

サンプルコード

import 'package:flutter/material.dart';

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

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

class _SamplePage006State extends State<SamplePage006> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FutureBuilder'),
      ),
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Text('FutureBuilder Success'),
              FutureBuilder(
                future: _successFuture(),
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.done) {
                    if (snapshot.hasError) {
                      return Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          const Icon(
                            Icons.info,
                            color: Colors.red,
                          ),
                          Text(snapshot.error?.toString() ?? ''),
                        ],
                      );
                    }
                    return Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        const Icon(
                          Icons.check_circle,
                          color: Colors.green,
                        ),
                        Text(snapshot.data?.toString() ?? ''),
                      ],
                    );
                  } else {
                    return const CircularProgressIndicator();
                  }
                },
              ),
              const SizedBox(height: 20),
              const Text('FutureBuilder Error'),
              FutureBuilder(
                future: _failureFuture(),
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.done) {
                    if (snapshot.hasError) {
                      return Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          const Icon(
                            Icons.info,
                            color: Colors.red,
                          ),
                          Text(snapshot.error?.toString() ?? ''),
                        ],
                      );
                    }
                    return Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        const Icon(
                          Icons.check_circle,
                          color: Colors.green,
                        ),
                        Text(snapshot.data?.toString() ?? ''),
                      ],
                    );
                  } else {
                    return const CircularProgressIndicator();
                  }
                },
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<String> _successFuture() async {
    await Future.delayed(const Duration(seconds: 2), () {});
    return 'Success!!';
  }

  Future<String> _failureFuture() async {
    await Future.delayed(const Duration(seconds: 2), () {});
    try {
      throw Exception('Error');
    } on Exception catch (e) {
      return Future.error(e);
    }
  }
}

結果

読込中はこんな感じ。

処理が終わったらこんな感じになります。

動画

公式リファレンス

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

#7 FadeTransition

FadeTransitionとは

シンプルなフェードイン・フェードアウトを実現するのにおすすめなのがFadeTransitionです。

使い方は、まずAnimationControllerを作成し、Animationを作成します。

作成したFadeTransitionウィジェットのopacityにそのAnimationを設定することで、FadeTransitionのchildに設定したウィジェットがフェードイン・フェードアウトするようになります。

アニメーションを再生するにはAnimationControllerforwardを呼び出します。

またAnimationControllerを1つだけ使う際はSingleTickerProviderStateMixinをMixinします。
2つ以上の場合はTickerProviderStateMixinをMixinします。

サンプルコード

import 'package:flutter/material.dart';

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

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

class _SamplePage007State extends State<SamplePage007>
    with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    );
    _animation = Tween<double>(
      begin: 0,
      end: 1,
    ).animate(_animationController);
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FadeTransition'),
      ),
      body: SafeArea(
        child: Center(
          child: FadeTransition(
            opacity: _animation,
            child: const FlutterLogo(
              size: 100,
            ),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (!_animationController.isCompleted ||
              !_animationController.isAnimating) {
            _animationController.forward();
          }
        },
        child: const Icon(Icons.play_arrow),
      ),
    );
  }
}

結果

ボタンを押してアニメーションを再生すると。。。

2秒間かけて、Flutterのロゴがフェードインしてきます。

動画

公式リファレンス

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

#8 FloatingActionButton

FloatingActionButtonとは

画面上の上に配置するボタンです。

さらにFloatingActionButtonを追加するのは簡単でScaffoldに追加するだけです。

またFloatingActionButtonLocationを使えば、BottomNavigationBarに埋め込めることができます。

サンプルコード

import 'package:flutter/material.dart';

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

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

class _SamplePage008State extends State<SamplePage008> {
  bool toggle = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FloatingActionButton'),
      ),
      body: const Center(
        child: Text('FloatingActionButton Sample'),
      ),
      bottomNavigationBar: BottomAppBar(
        color: Colors.yellow,
        child: Container(height: 50),
      ),
      floatingActionButtonLocation: toggle
          ? FloatingActionButtonLocation.centerDocked
          : FloatingActionButtonLocation.endFloat,
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            toggle = !toggle;
          });
        },
        child: const Icon(Icons.loop),
      ),
    );
  }
}

結果

通常は右下がFloatingActionButtonの位置ですが。。。

設定によっては真ん中にしてBottomNavigationBarにも埋め込むことができます。

動画

公式リファレンス

FloatingActionButton class - material library - Dart API
API docs for the FloatingActionButton class from the material library, for the Dart programming language.

さいごに

Animation系はあんまり使わないなぁ。

おすすめ参考書

リンク

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

コメント

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