Studyplus Engineering Blog

スタディプラスの開発者が発信するブログ

Widgetbookを使ってFlutterのデザイン調整を効率化する方法

クライアントグループの隅山です。 Flutterの標準Widgetをデザイン調整する際、どの範囲でデザイン調整できるのかをデザイナーと頻繁にやり取りすることがありました。 その中でWidgetbookというツールを活用することで、デザイン調整にかかる工数を大幅に削減できました。

今回はWidgetbookとはどのようなものか、そしてWidgetbookをどのように活用したのかを紹介します。

Widgetbookとは

WidgetbookはFlutterで開発されたUIコンポーネントの管理とプレビューを簡単に行えるツールです。 リアルタイムでプレビューを変更しデザインを確認できるため、コミュニケーションが効率化され、デザインの品質が向上します。

pub.dev

Widgetbookの主な機能は以下の通りです。

  • コンポーネントのカタログ化
  • リアルタイムプレビュー

WidgetbookではUIコンポーネントをカタログのように整理できます。 さらに、UIコンポーネントのデザイン変更をリアルタイムにプレビューできるため、迅速にデザイン調整が行えます。 デザイナーと開発者がプレビューを見ながら作業することで、認識のズレを防ぐことができます。

Widgetbookの導入

Widgetbookはgeneratorも一緒に導入することで簡単に実装できます。

flutter pub add widgetbook widgetbook_annotation
flutter pub add dev:widgetbook_generator

WidgetbookにAddonsを設定することで、画面設定の切り替えが簡単に行えるため導入しました。

import 'package:flutter/material.dart';
import 'package:widgetbook/widgetbook.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;

import 'widgetbook.directories.g.dart';

@widgetbook.App()
class WidgetbookApp extends StatelessWidget {
  const WidgetbookApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Widgetbook.material(
      directories: directories,
      addons: [
        InspectorAddon(
          enabled: false,
        ),
        MaterialThemeAddon(
          themes: [
            WidgetbookTheme(
              name: 'Light',
              data: lightTheme,
            ),
            WidgetbookTheme(
              name: 'Dark',
              data: darkTheme,
            ),
          ],
        ),
        TextScaleAddon(
          scales: [0.8, 1.0, 1.2, 2.0],
          initialScale: 1.0,
        ),
        ZoomAddon(
          initialZoom: 1.0,
        ),
        DeviceFrameAddon(
          devices: [
            Devices.android.bigPhone,
            Devices.android.largeTablet,
            Devices.ios.iPhone13,
            Devices.windows.wideMonitor,
            Devices.macOS.wideMonitor,
          ],
        ),
        AccessibilityAddon(),
      ],
    );
  }
}

次に表示したいUIコンポーネントをアノテーションを利用して作成します。

import 'package:flutter/material.dart';
import 'package:widgetbook/widgetbook.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;

@widgetbook.UseCase(
  name: 'filledButton',
  type: FilledButton,
  path: '[Component]/[Button]',
)
Widget filledButtonUseCase(BuildContext context) {
  final disabled = context.knobs.boolean(label: 'Disabled');
  final hasIcon = context.knobs.boolean(label: 'Icon');
  final text = context.knobs.string(
    label: 'Text',
    initialValue: 'ボタン',
  );

  return Center(
    child: FilledButton.icon(
      onPressed: disabled ? null : () {},
      icon: hasIcon ? const Icon(Icons.add_outlined) : null,
      label: Text(text),
    ),
  );
}

最後にコードを自動生成し、実行すると以下のような画面が表示されます。

Widgetbookでのデザイン調整の方法

今回はFilledButtonのデザイン調整範囲を例として紹介します。 デザイン調整範囲を確認するために、まずはButtonStyleのパラメータを確認します。

api.flutter.dev

次に確認したいパラメータをWidgetbookで定義して調整できるようにします。 すべてのパラメータを変更できるのが理想ですが、ここではいくつかピックアップします。

Widget filledButtonUseCase(BuildContext context) {
  ...
  final backgroundColor = context.knobs.colorOrNull(label: 'Background Color');
  final elevation = context.knobs.doubleOrNull.slider(label: 'Elevation');
  final padding = EdgeInsets.symmetric(
    horizontal: context.knobs.double.slider(label: 'Horizontal Padding', initialValue: 16),
    vertical: context.knobs.double.slider(label: 'Vertical Padding', initialValue: 8),
  );
  final alignment = context.knobs.listOrNull(
    label: 'Alignment',
    options: [
      Alignment.centerLeft,
      Alignment.center,
      Alignment.centerRight,
    ],
  );

  return Center(
    child: FilledButton.icon(
      ...
      style: ButtonStyle(
        backgroundColor: WidgetStateProperty.all(backgroundColor),
        elevation: WidgetStateProperty.all(elevation),
        padding: WidgetStateProperty.all(padding),
        alignment: alignment,
      ),
    ),
  );
}

上記の設定すると、以下の画面のように設定項目が追加されます。

このように実装することで、リアルタイムにデザイン確認できるプレビューを作成できます。 これを用いてデザイナーと同期的に作業することや、デザイナーにWidgetbookアプリを渡して確認してもらうこともできます。

Widgetbookを利用した効果

Flutterはホットリロード機能があるため、デザイン修正してすぐに実行できますが、そのためにはデザイナーと同期的にデザイン調整の作業する必要がありました。 しかし、Widgetbookを利用することにより、デザイナーがアプリで実際利用するUIコンポーネントをリアルタイムで確認しながらデザイン調整できるようになりました。

ここでは詳しく触れませんでしたが、WidgetbookのInspectorを用いることで以下のことも確認できます。

  • Widget同士のマージンを可視化
  • Widgetに適用されている色トークンを確認

課題としては以下が挙げられます。

  • Zoomを利用するとInspectorのUIコンポーネントの位置がずれる
  • KnobsのList項目の名称が定義した型になってしまう
    • 例えば、TextStyleの場合、List項目の名称がTextStyleの型として表示される

しかし、List項目もRecord型などで実装してリスト項目を見やすくできるため、全体的に見て導入して非常に便利になりました。