Flutterでウィジェットのカタログを作れるWidgetbookの基本的な使い方をまとめました。
widgetbook 3.7.1
はじめに
Widgetbookを使うと、下図のデモアプリのキャプチャのように、ウィジェット(UI)のカタログを作ることができます。
カタログを作ることでウィジェットの設計や再利用ルールがわかりやすくなり、またいちいちアプリを最初の画面から起動しなくてもウィジェットの動作をテストすることができるようになります。
さらにこのカタログを作る過程でビジネスロジックを切り離す必要があるため、結果的に保守性の高い設計にもつながります。
本記事ではこのWidgetbookの使い方についてまとめます。
なお、Widgetbookにはコードジェネレータを使って開発するパターン(Generator Approach)と使わないで開発するパターン(Manual Approach)がありますが、本記事では使うパターンで説明を進めます。
またクラウド機能(Widgetbook Cloud)については本記事では取り扱いません。
インストール〜ビルドまで
インストールは以下の通り行います。
flutter pub add widgetbook_annotation widgetbook flutter pub add widgetbook_generator build_runner --dev
インストールしたら早速カタログ用のアプリケーションを作っていきます。
以下のファイルを作成します。名前は任意でOKです。
// lib/widgetbook.dart(名前は任意でOK) import 'package:flutter/material.dart'; import 'package:widgetbook/widgetbook.dart'; import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; // コード生成するまではコンパイルエラーになりますが気にせず次のステップに進んでください import 'widgetbook.directories.g.dart'; void main() { runApp(const WidgetbookApp()); } // 以下ボイラープレート @widgetbook.App() // アノテーションをつける class WidgetbookApp extends StatelessWidget { const WidgetbookApp({super.key}); @override Widget build(BuildContext context) { return Widgetbook.material( // ルートのウィジェットはこれを使う directories: directories, // ここは自動生成されます addons: [], ); } }
次にTerminalから以下を実行してコード生成を走らせます。
flutter pub run build_runner build
ちなみに以下のようにすると毎回上記のように実行をしなくても、自動的にコード生成が行われます。
(詳細はbuilde_runnerの仕様になるので本記事では割愛します。)
flutter pub run build_runner watch
コード生成をするとコンパイルエラーが消えるので、先ほど作ったwidgetbook.dartを実行します。
IDEのGUIからでも何でも大丈夫ですが、Terminalから実行するなら以下のような感じです。
flutter run -t lib/widgetbook.dart -d macos
下図のような画面(ウィジェットブック)が表示されたら完了です。
コンポーネントとユースケースを追加する
次にコンポーネントとユースケース(カタログの項目)を追加します。
コンポーネントとユースケースは後で説明するとして、ひとまずlib/srcディレクトリにcontainers.dartを以下のように作成します。
// lib/src/components/containers.dart import 'package:flutter/material.dart'; import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; // UseCaseアノテーションをつける @widgetbook.UseCase( // nameにはこのコンポーネントにおけるユースケース(後述)の名前をつける name: 'with green color', // typeには対象のウィジェットの型を指定する type: Container, ) // Containerコンポーネント、緑色の状態を表すユースケース Widget greenContainerUseCase(BuildContext context) { return Column( children: [ Container( color: Colors.green, child: const SizedBox.square( dimension: 100, ), ), ], ); } @widgetbook.UseCase( name: 'with red color', type: Container, ) Widget redContainerUseCase(BuildContext context) { return Column( children: [ Container( color: Colors.red, child: const SizedBox.square( dimension: 100, ), ), ], ); }
コードを変更した後はコード生成が必要なので、上で説明した方法でbuild_runnerを使ってコード生成します。
コード生成後、アプリを実行すると以下の結果を得ることができます。
Container
コンポーネントと、その下にwith green color
とwith red color
という二つのユースケースが作成されていることを確認できました。
このように、同じウィジェットの別の状態(上記の緑状態と赤状態)のことをユースケースと呼び、UseCaseアノテーションのname
で指定した名前で項目化されます。
また上記のContainerのように、ユースケースはUseCaseアノテーションで指定したtype
のウィジェット毎にまとめられますが、これをコンポーネントと呼びます(Figmaのコンポーネントと同じイメージ)。
ちなみに、 ウィジェットブックのアプリのナビゲーションにおける階層は、対象のウィジェット(typeに指定したウィジェット)のプロジェクトにおける階層に合わせて決まります。(将来的にはもっと柔軟にできるようにする予定とのこと)
アドオン
アドオン機能を使うとWidgetbookの環境をカスタムできます。
例えば下図のようにWidgetbookにスマートフォンの枠をつけたり、アラインメントを調整したり、グリッドをつけたりといったことができます。
またアドオンによっては右側のAddonsメニューから実行中に設定を変更できます。
実装としては、Widgetbookのコンストラクタのaddons引数に適用したいアドオンのインスタンスを渡します。
以下はデバイス(スマートフォンなど)の枠を表示するDeviceFrameAddon
を設定した例です。
// widgetbook.dart import 'package:flutter/material.dart'; import 'package:widgetbook/widgetbook.dart'; import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; import 'widgetbook.directories.g.dart'; void main() { runApp(const WidgetbookApp()); } @widgetbook.App() class WidgetbookApp extends StatelessWidget { const WidgetbookApp({super.key}); @override Widget build(BuildContext context) { return Widgetbook.material( directories: directories, addons: [ // スマホなどのデバイスのフレームを表示し、その中にユースケースを表示する DeviceFrameAddon( devices: [ Devices.ios.iPhoneSE, Devices.ios.iPhone13, ], initialDevice: Devices.ios.iPhone13, ), ], ); } }
その他、実装されているアドオンとその概要は以下のとおりです。
名前 | 概要 |
---|---|
Alignmentアドオン | 表示するユースケースのアラインメントを変更する(中央寄せとか) |
DeviceFrameアドオン | スマートフォンなどのデバイスの枠を画面上に表示する |
Builderアドオン | 全てのユースケースをラップするWidgetを指定できる |
Gridアドオン | 背景にグリッドを表示する |
Localizationアドオン | ローカリゼーションの設定を切り替えることができる |
TextScaleアドオン | テキストのスケールを変更した状態でユースケースを表示できる |
Themeアドオン | テーマを変更した状態でユースケースを表示できる |
Zoomアドオン | ズームの度合いを変更した状態でユースケースを表示できる |
Inspectorアドオン | 指定したWidgetの色やサイズ、パディングなどを表示する検査ツールをWidgetbook内に表示する |
Accessibilityアドオン | https://pub.dev/packages/accessibility_toolsによるアクセシビリティチェックをできる |
詳細はドキュメントを参照してください。独自のアドオンも作れます。
ノブ
ノブは、任意の値をWidgetbookのGUIから調整できる機能です。
例えば下図のように、サイズをノブで調整できます。
コードは以下のように書きます。
import 'package:flutter/material.dart'; import 'package:widgetbook/widgetbook.dart'; import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; @widgetbook.UseCase( name: 'with green color', type: Container, ) Widget greenContainerUseCase(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( color: Colors.green, child: SizedBox.square( // ノブを使ってサイズを変更できるようにする dimension: context.knobs.double.slider( label: 'Size', min: 50, max: 200, initialValue: 100, ), ), ), ], ); }
上記ではdouble型の値をスライダーで変更できるノブを使っていますが、以下の型を扱うノブも実装されています。
- bool
- int
- double
- String
- Duration
- DateTime
- Color
- 任意の型のリスト(複数の選択肢から一つドロップダウンで選ぶノブを表示できる)
また、独自のノブを作成することもできます。
詳細はドキュメントを参照してください。