PR

[Flutter]Flutter Widget of the Week「#136 FutureBuilder(Take 2)」、「#137 NavigationBar」、「#138 go_router」

Flutter

はじめに

前回はFlutter Widget of the Weekの「#133 Shortcuts」、「#134 Actions」、「#135 firebase_ui_auth」を紹介しました。

今回はその続きで「#136 FutureBuilder(Take 2)」、「#137 NavigationBar」、「#138 go_router」の3つです。

前回の記事はこちら

またGitHubにも公開しています。

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

Flutter Widget of the Week

環境

  • Flutter 3.7.0

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

#136 FutureBuilder(Take 2)

FutureBuilderとは

#6 FutureBuilderと同じです。なぜTake 2が必要なのかは不明です。

サンプルコード

import 'package:flutter/material.dart';

class SamplePage136 extends StatefulWidget {
  const SamplePage136({
    super.key,
  });

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

class SamplePage136State extends State<SamplePage136> {
  late Future<String> _success;
  late Future<String> _failure;

  @override
  void initState() {
    super.initState();

    _success = _successFuture();
    _failure = _failureFuture();
  }

  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);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FutureBuilder(Take 2)'),
      ),
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Text('FutureBuilder Success'),
              FutureBuilder(
                future: _success,
                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: _failure,
                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();
                  }
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

結果

動画

公式リファレンス

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

#137 NavigationBar

NavigationBarとは

機能としてはBottomNavigationBarと全く同じですが、

BottomNavigationBarはMaterial 2、NavigationBarはMaterial 3のデザインに準拠している違いがあります。

サンプルコード

import 'package:flutter/material.dart';

class SamplePage137 extends StatefulWidget {
  const SamplePage137({
    super.key,
  });

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

class SamplePage137State extends State<SamplePage137> {
  int _selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('NavigationBar'),
      ),
      bottomNavigationBar: NavigationBar(
        selectedIndex: _selectedIndex,
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          NavigationDestination(
            icon: Icon(Icons.explore),
            label: 'Explore',
          ),
          NavigationDestination(
            icon: Icon(Icons.person),
            label: 'Profile',
          ),
          NavigationDestination(
            icon: Icon(Icons.settings),
            label: 'Settings',
          ),
        ],
        onDestinationSelected: (value) {
          setState(() {
            _selectedIndex = value;
          });
        },
      ),
    );
  }
}

結果

動画

公式リファレンス

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

#138 go_router

go_routerとは

FlutterのNavigation2.0の実装が簡単になるパッケージです。

最初は有志のパッケージでしたが公式のパッケージになりました。

サンプルコード

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

class SamplePage138 extends StatefulWidget {
  const SamplePage138({
    super.key,
  });

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

class SamplePage138State extends State<SamplePage138> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: router,
    );
  }

  final router = GoRouter(
    initialLocation: '/main',
    routes: [
      GoRoute(
        path: '/main',
        builder: (context, state) => const SamplePage138Main(),
        routes: [
          GoRoute(
            path: 'sub1',
            builder: (context, state) => const SamplePage138Sub1(),
          ),
          GoRoute(
            path: 'sub2',
            builder: (context, state) => const SamplePage138Sub2(),
            routes: [
              GoRoute(
                path: 'sub3',
                builder: (context, state) => const SamplePage138Sub3(),
              ),
            ],
          ),
        ],
      ),
    ],
  );
}

class SamplePage138Main extends StatelessWidget {
  const SamplePage138Main({
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('go_router'),
      ),
      body: SafeArea(
        child: ListView(
          children: [
            ListTile(
              title: const Text('Sub1'),
              trailing: const Icon(Icons.navigate_next),
              onTap: () {
                context.go('/main/sub1');
              },
            ),
            ListTile(
              title: const Text('Sub2'),
              trailing: const Icon(Icons.navigate_next),
              onTap: () {
                context.go('/main/sub2');
              },
            ),
          ],
        ),
      ),
    );
  }
}

class SamplePage138Sub1 extends StatelessWidget {
  const SamplePage138Sub1({
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Sub1'),
      ),
    );
  }
}

class SamplePage138Sub2 extends StatelessWidget {
  const SamplePage138Sub2({
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Sub2'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          context.go('/main/sub2/sub3');
        },
        child: const Icon(Icons.navigate_next),
      ),
    );
  }
}

class SamplePage138Sub3 extends StatelessWidget {
  const SamplePage138Sub3({
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Sub3'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          context.go('/main');
        },
        child: const Icon(Icons.home),
      ),
    );
  }
}

結果

動画

公式リファレンス

go_router | Flutter package
A declarative router for Flutter based on Navigation 2 supporting deep linking, data-driven routes and more

さいごに

Flutter Widget of the WeekPackage of the Weekしかやらないのだろうか?

おすすめ参考書

リンク

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

コメント

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