Playground

Flutterで使えるUIカタログを使ってみた( widgetbook編 )

Playground
この記事は約15分で読めます。
スポンサーリンク
お久しぶりです。みやかわです。
最近 Flutter をお勉強中です。
いい感じに作って完成!やったぜ!という日が続いていますが、やはり一度はちゃんと作ってAppストアなりに公開したいものです。
そうなると、バグをなくすためにテストやら維持をするためにアドセンス、効率よく作るにはどうすればよいか等々を考える必要があります。
今回は効率よく作る一つのものとして Flutter で使えるUIカタログについて書いていきます。
FlutterのUIカタログで有名所は widgetbook、 storybook_flutter、 monarchplaybook かと思います。
今回は widgetbook について使い方を書いていきます。

スポンサーリンク

widget book とは

widgetbook.io が作っている UIコンポーネントの管理ツールです。
TwitterでFluterのUIカタログについて検索をかけると使っている人がおおいようです。
公式がYoutubeで使い方を発信しているので大変わかりやすいです。

早速試す

サンプルの用意

今回使うものは以下のリポジトリに入れてあります。
はじめは以下のような構成にします。
% tree my_sample_widget_book/lib 
my_sample_widget_book/lib
├── app.dart
├── main.dart
├── pages
│   └── main_page
│   └── main_page.dart
└── widgets
├── my_card
│   └── my_card.dart
└── my_text
└── my_text.dart
これを起動すると以下のようになります。

widgetbookのインストール

いつものようにライブラリをインストールコマンドを叩きます。
$ flutter pub add widgetbook --dev
1.0.2 が入りました。
## pubspec.yaml

dev_dependencies:
flutter_test:
sdk: flutter

# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^1.0.0
widgetbook: ^1.0.2

UIカタログを作る

プロジェクトのルートに widgetbook というフォルダを作成し、main.dart を作成します。
widgetbook/main.dart にUIカタログを作っていきます。
※ フォルダ名はテキトーで良いです。ここでは widgetbook というフォルダを作ります。
% tree widgetbook
widgetbook
└── main.dart

最初に空のUIカタログを作ります。

以下のコードを widgetbook/main.dartにコピペします。
import 'package:flutter/material.dart';
import 'package:widgetbook/widgetbook.dart';

class WidgetbookhotReload extends StatelessWidget {
  const WidgetbookhotReload({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Widgetbook(
        categories: const [], appInfo: AppInfo(name: 'Recipe App')); // name がUIカタログの題名
  }
}

void main() {
  runApp(const WidgetbookhotReload());
}

その後、 widgetbook/main.dart を起動します。

$ flutter run -t widgetbook/main.dart -d chrome
コマンドを実行すると、Chromeが立ち上がり、UIカタログが表示されます。

自作したWidgetをUIカタログに乗せる

では、作成したWidgetをUIカタログに表示します。
以下のコードをコピペ
import 'package:flutter/material.dart';
import 'package:my_sample_widget_book/pages/main_page/main_page.dart';
import 'package:my_sample_widget_book/widgets/my_card/my_card.dart';
import 'package:my_sample_widget_book/widgets/my_text/my_text.dart';
import 'package:widgetbook/widgetbook.dart';

class WidgetbookhotReload extends StatelessWidget {
  const WidgetbookhotReload({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Widgetbook(
      appInfo: AppInfo(name: 'Recipe App'),
      lightTheme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      categories: [
        // widgets 関連
        WidgetbookCategory(
          name: 'widgets',
          widgets: [
            // MyCard の UIカタログ
            WidgetbookWidget(name: 'MyCard', useCases: [
              WidgetbookUseCase(
                name: 'Default',
                builder: (context) => const MyCard(),
              )
            ]),
            // MyText の UIカタログ
            WidgetbookWidget(name: 'MyText', useCases: [
              WidgetbookUseCase(
                name: 'Test1',
                builder: (context) => const MyText(param: 'test'),
              ),
              WidgetbookUseCase(
                name: 'Test2',
                builder: (context) => const MyText(param: 'hoge'),
              )
            ]),
          ],
        ),
        // Pages 関連
        WidgetbookCategory(name: 'Pages', widgets: [
          // MainPage の UIカタログ
          WidgetbookWidget(name: 'mainPage', useCases: [
            WidgetbookUseCase(
                name: 'Default', builder: (context) => const MainPage())
          ])
        ])
      ],
    );
  }
}

void main() {
  runApp(const WidgetbookhotReload());
}
実行すると、以下のように自作したwidgetが表示されます。

もっとかんたんにUIカタログを作りたい

先程の解説でUIカタログを作ることができました。
しかしながら、Widgetを作るたびに widgetbook/main.dart を更新する必要が出てきます。
正直めんどいですよね。
ということで、widgetbook/main.dart 相当のものを自動で生成してくれる方法があります。

簡単に作ることができるライブラリのインストール

$ flutter pub add widgetbook_annotation --dev
$ flutter pub add widgetbook_generator --dev
$ flutter pub add build_runner --dev

インストール後の pubspec.yaml

dev_dependencies:
  flutter_test:
    sdk: flutter

  # The "flutter_lints" package below contains a set of recommended lints to
  # encourage good coding practices. The lint set provided by the package is
  # activated in the `analysis_options.yaml` file located at the root of your
  # package. See that file for information about deactivating specific lint
  # rules and activating additional ones.
  flutter_lints: ^1.0.0
  widgetbook: ^1.0.2
  widgetbook_generator: ^1.0.2
  widgetbook_annotation: ^1.0.0
  build_runner: ^2.1.5

実装してみる

はじめに、widgetbookの大枠を作っていきます。
lib/main.dart を以下のように編集。
ポイントは @WidgetbookTheme@WidgetbookApp です。
@WidgetbookTheme で テーマを設定し、 @WidgetbookApp で表示するレイアウトを定義しています。
import 'package:flutter/material.dart';
import 'package:my_sample_widget_book/app.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart';

// テーマ設定
@WidgetbookTheme.dark()
ThemeData darkTheme() => ThemeData.dark();
@WidgetbookTheme.light()
ThemeData lightTheme() => ThemeData.light();

// UIカタログの名前と出漁するデバイス設定
@WidgetbookApp(name: 'Recipe App', devices: [Apple.iPhone12, Samsung.s21ultra])
void main() {
  runApp(const App());
}
次は widget ごとにUIカタログを定義します。
MyText() を例にすると以下のような感じです。
MyText の Widget があるフォルダに my_test_widgetbook.dart を作成。
% tree lib/widgets/  
lib/widgets/
├── my_card
│   └── my_card.dart
└── my_text
    ├── my_test_widgetbook.dart
    └── my_text.dart

※ my_test.widgetbook.dart のように my_test と widgetbook の間をピリオドにすると自動生成しないので注意。

そして lib/widgets/my_test_widgetbook.dart に以下をコピペ

import 'package:flutter/material.dart';
import 'package:my_sample_widget_book/widgets/my_text/my_text.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart';

@WidgetbookUseCase(name: 'Test1', type: MyText) // ユースケース名
Widget myTestUseCase1(BuildContext context) {
  return const MyText(param: 'test');
}

@WidgetbookUseCase(name: 'Test2', type: MyText)
Widget myTestUseCase2(BuildContext context) {
  return const MyText(param: 'hoge');
}

 

これで MyTest widget の UIカタログの準備は完了です。
MyCard Widget と MainPage についても同様のことをしていきます。
作ったものは github に上がっています。
作成後し終えたら、早速生成していきます。
ビルドランナーを走らせてコードを自動生成します。
% flutter pub run build_runner build
[INFO] Generating build script...
[INFO] Generating build script completed, took 355ms

[INFO] Precompiling build script......
[INFO] Precompiling build script... completed, took 5.0s

[INFO] Initializing inputs
[INFO] Building new asset graph...
[INFO] Building new asset graph completed, took 504ms

[INFO] Checking for unexpected pre-existing outputs....
[INFO] Checking for unexpected pre-existing outputs. completed, took 1ms

[INFO] Running build...
[INFO] Generating SDK summary...
[INFO] 2.9s elapsed, 0/8 actions completed.
[INFO] Generating SDK summary completed, took 2.9s

[INFO] 4.0s elapsed, 0/8 actions completed.
[INFO] 5.1s elapsed, 0/8 actions completed.
[INFO] 6.1s elapsed, 0/8 actions completed.
[INFO] 11.3s elapsed, 0/8 actions completed.
[INFO] Running build completed, took 11.7s

[INFO] Caching finalized dependency graph...
[INFO] Caching finalized dependency graph completed, took 36ms

[INFO] Succeeded after 11.8s with 5 outputs (24 actions)
成功すると、 lib フォルダに main.widgetbook.dart というファイルが生成されます。
こいつを開くと UIカタログが表示されます。
% flutter run -t lib/main.widgetbook.dart -d chrome

どうやらフォルダ階層に合わせてUIカタログも振り分けられるらしいようです。
ちょっとアクセスしづらい。。。
ともあれ、これで自動でUIカタログを作ることができました。

まとめ

数あるUIカタログの中で今回はwidgetbookを使ったUIカタログの方法を書いてみました。
自動でUIカタログが生成されるのはホント楽で良いです。
また今回は詳細な設定については省きました。細かくチューニングしたいという人は公式を参照してください。
それでは今度は playbookかstorybook-flutter についても書こうと思います。

コメント

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