アプリの画面数が増えると、ホットリロードが効かない画面が出てきてUI改修が難しくなることがある。その対策として、Flutter版StorybookであるWidgetbookを導入した。以下にその実装内容をまとめる。
導入したPR
実際の変更内容は以下のPRを参照。
Widgetbookとは
WidgetbookはFlutterでUIカタログを作成するためのツール。UIコンポーネントの状態を簡単に切り替えながら確認できる。 詳細は公式サイトを参照。
実装
初期セットアップ
公式のクイックスタートガイドを参考に導入を進めた。 docs.widgetbook.io
コマンドを実行すると、以下のようなフォルダ構成が生成される。
app/ └── widgetbook ├── README.md ├── analysis_options.yaml ├── android ├── build ├── ios ├── lib ├── linux ├── macos ├── pubspec.lock ├── pubspec.yaml ├── web ├── widgetbook.iml └── windows
コンポーネントの追加
自作のButtonコンポーネントをWidgetbookに追加するため、以下のコードを作成。
■ dart/app/widgetbook/lib/button.dart/lib/button.dart
import 'package:flutter/material.dart'; import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; // Import the widget from your app import 'package:stockkeeper/components/button/button.dart'; // ← ここが自作のButtonコンポーネント @widgetbook.UseCase(name: 'Default', type: Button) Widget buildCoolButtonUseCase(BuildContext context) { return Button(title: 'Hello', onPressed: () {}); }
コード生成
以下のコマンドを実行し、Widgetbook用のコードを生成する。
$ dart run build_runner build -d
これにより、widgetbook/lib/main.directories.g.dartが自動生成される。
動作確認
widgetbook/lib/main.goをVSCodeで開き、F5キーを押してデバッグを実行する。Chromeが起動し、以下のようにUIカタログが表示される。
Providerを使ったMock対応
アプリでProviderを使用している場合、WidgetbookでもMockを作成して対応可能。公式ガイドを参考に実装した。
以下は、ProviderをMockしてコンポーネントを表示する例。
■ dart/app/widgetbook/lib/components/item/input.dart
import 'package:flutter/material.dart'; import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; import 'package:stockkeeper/components/item/input.dart'; import 'package:mocktail/mocktail.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:stockkeeper/providers/graphql.dart'; // Mockクラスの作成 class FakeQueryOptions extends Fake implements QueryOptions {} class MockGraphQLClient extends Mock implements GraphQLClient {} @widgetbook.UseCase(name: 'Default', type: Input) Widget buildInputUseCase(BuildContext context) { final mockGraphQLClient = MockGraphQLClient(); // ←ProviderのMockを作成して when(() => mockGraphQLClient.query(any())).thenAnswer( (_) async => QueryResult( options: QueryOptions(document: gql('')), source: QueryResultSource.network, data: null), ); return ProviderScope( overrides: [graphqlClientProvider.overrideWithValue(mockGraphQLClient)], // ←Providerを設定 child: Input( onPressed: (item) {}, loading: false, ), ); }
導入の効果
- 各コンポーネントの状態をサイドメニューから簡単に切り替え可能
- UI改修の効率が向上
- Providerを使用したコンポーネントもMockで柔軟に対応可能
Widgetbookの導入により、FlutterアプリのUI開発が効率化された。画面数が多いプロジェクトでは、UIカタログを用いた開発が特に有効だと感じた。