【Flutter】ウィジェットのカタログを作れるWidgetbookの基本的な使い方まとめ

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を実行します。
IDEGUIからでも何でも大丈夫ですが、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 colorwith 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によるアクセシビリティチェックをできる

詳細はドキュメントを参照してください。独自のアドオンも作れます。

docs.widgetbook.io

ノブ

ノブは、任意の値を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
  • 任意の型のリスト(複数の選択肢から一つドロップダウンで選ぶノブを表示できる)

また、独自のノブを作成することもできます。

詳細はドキュメントを参照してください。

docs.widgetbook.io

参考

www.widgetbook.io