【Flutter】ステップバイステップのUIをStepperで実装

対象者

  • Flutterを学び始めたエンジニアやIT専門職で、UIにStepperを実装する必要がある人
  • 自己学習を通じて新しい技術を習得し、自身のスキルを向上させたいと考えている人
  • 一週間以内にStepperの基本的な実装とカスタマイズ方法を理解し、適用できるようになりたいと考えている人

はじめに

Stepperというのは、日本語で「ステップ」や「段階」という意味です。プログラムの世界では一般的に複数の処理を順序立てて実行することを示します。
Flutterにおいては、ユーザーが一連のステップを順番に進むことを支援するウィジェットです。そのため、複数のフォーム入力や設定手順などをステップバイステップで進行するユーザーインターフェースを作成することができます。

FlutterでStepperをうまく活用すると、ユーザー体験を大幅に向上させることができます。Stepperはユーザーが一連の手順を順に進むことを可能にするため、フォーム入力、アプリの新規ユーザーオンボーディング、複雑なタスクの手順化など、多くの場面で有効です。しかし、その実装にはいくつかの細部があり、それらを把握することが重要です。

この記事では、FlutterでStepperを効果的に実装し、カスタマイズする方法を詳しく説明します。色の変更、アイコン画像の変更など、Stepperをあなたのアプリに完全にフィットさせるためのテクニックを紹介します。さらに、Stepperを活用した具体的な事例として、フォーム作成やオンボーディングフローの実装を取り上げます。

また、FlutterでStepperを簡単に実装するためのパッケージ、「im_stepper」と「easy_stepper」も紹介します。これらのパッケージを利用すると、簡単なコードでStepperをカスタマイズし、独自のフローを実装することができます。

FlutterのStepper実装を学ぶためのあなたの時間を最大限に活用するために、この記事はわかりやすく、具体的な説明を心掛けています。今までの経験と知識を活かし、さらに一歩前進しましょう。あなたのFlutterスキルを次のレベルに引き上げるための情報がここには詰まっています。それでは、一緒に学んでいきましょう。

Stepperとは何か?

Stepperは、Flutterのマテリアルデザインウィジェットの一つで、ユーザーが一連のステップを通じた進行状況を視覚的に把握するのに役立ちます。特に、フォームのようなものを完成させるために一つ以上のステップを必要とする場合や、一つのステップが別のステップの完了に依存する場合に有用です。

Stepperの基本的な役割

Stepperの主な役割は、ユーザーがタスクの進行状況を明確に理解するのを助けることです。ステップ間での遷移は、各ステップが完了したときに自動的に次のステップに進むように制御することが可能です。この仕組みにより、ユーザーは何が必要で、全体のプロセスの中でどこにいるのかを確認することができます。

例えば、以下のコードは基本的なステップの設定を示しています。

Stepper(
  steps: const <Step>[
    Step(
      title: Text('Step 1'),
      content: SizedBox(
        height: 50.0,
        child: Center(
          child: Text('This is Step 1'),
        ),
      ),
    ),
    Step(
      title: Text('Step 2'),
      content: SizedBox(
        height: 50.0,
        child: Center(
          child: Text('This is Step 2'),
        ),
      ),
    ),
  ],
)

この例では、Stepperウィジェットが2つのステップを持つことを示しています。

Stepperが適用される場面

Stepperは、特に複数の入力フィールドを持つフォームの作成において有用です。ユーザーがフォーム全体を一度に把握するのを助け、各ステップを順番に完了することで全体のタスクを終えられるようにします。また、オンボーディングフローやセットアップウィザードのような複数のステップを含むユーザーインターフェイスを設計する際にも利用されます。

具体的には、オンラインショッピングアプリケーションの注文プロセスでの商品選択、配送情報の入力、支払い方法の選択といったステップの管理に使用することが可能です。このような用途では、Stepperを使用することでユーザーのタスクの複雑さを軽減させます。

Stepperの構造と設定

Stepperのタイプ:水平方向と垂直方向

FlutterのStepperウィジェットは、水平方向または垂直方向の両方で表示することができます。これはStepperTypeというプロパティで指定します。デフォルトは垂直ですが、StepperType.horizontalを指定することで水平方向にすることができます。この選択はユーザーインターフェースの全体的なデザインやユーザーの使いやすさに応じて選択されるべきです。

Stepper(
  type: StepperType.horizontal, // Or StepperType.vertical
  steps: _steps,
)

上記のコードスニペットは、Stepperウィジェットを水平方向に設定する方法を示しています。

Stepperのステップ設定方法

Stepperウィジェットはstepsという名前のリストを持ちます。このリストには、Stepというオブジェクトのコレクションが含まれており、それぞれがステップを定義します。Stepオブジェクトはtitleとcontentという2つの主要なプロパティを持ち、それぞれステップのラベルとステップの内容を定義します。

Stepper(
  steps: [
    Step(
      title: Text('Step 1'),
      content: Text('This is the first step'),
    ),
    Step(
      title: Text('Step 2'),
      content: Text('This is the second step'),
    ),
  ],
)

このコードスニペットは、Stepperに2つのステップを設定する例を示しています。

このように、FlutterのStepperウィジェットは非常に柔軟で、さまざまなユーザーインターフェースの要件を満たすために設定をカスタマイズすることができます。

FlutterにおけるStepperの実装

FlutterでStepperを作成する基本的な手順

Stepperの実装は直感的で、複数のステップを有するプロセスを一貫性と明確さを持ってユーザに提供することが可能です。以下は、FlutterでStepperを実装する基本的な手順です。

まず、Stepperウィジェットを宣言し、その中にステップを表すstepsというリストを定義します。Stepオブジェクトはtitlecontentという2つのパラメータを必要とし、それぞれがステップのラベルと内容を表現します。

Stepper(
  steps: [
    Step(
      title: Text('Step 1'),
      content: Text('This is the first step'),
    ),
    Step(
      title: Text('Step 2'),
      content: Text('This is the second step'),
    ),
  ],
)

このコードは、二つのステップを持つStepperを作成します。

Stepperのカスタマイズ方法

Stepperは高度にカスタマイズ可能で、その見た目や動作はあなたの要件に合わせて調整できます。例えば、Stepperの方向は水平または垂直にすることができます。これはtypeというプロパティで設定します。デフォルトは垂直方向ですが、StepperType.horizontalを指定することで水平方向にもできます。

また、ステップ間の遷移はcurrentStepプロパティとonStepTappedコールバックを使用して管理できます。currentStepは現在アクティブなステップのインデックスを表し、onStepTappedはユーザーがステップをタップした時に呼び出される関数です。以下の例では、ユーザーがステップをタップしたときにそのステップに移動するようにしています。

int _currentStep = 0;

Stepper(
  currentStep: _currentStep,
  onStepTapped: (step) {
    setState(() {
      _currentStep = step;
    });
  },
...
)

以上のように、FlutterのStepperは、見た目や動作のカスタマイズにより多様な要件を満たすことが可能です。その使いやすさと柔軟性により、ユーザーが一貫した体験を得ることができ、プログラムの複

Stepperの色の変更

Stepperの色を変更することで、アプリケーションのデザインやブランドイメージに一致するように調整することが可能です。Flutterでは、ThemeDataを使用してアプリ全体のテーマを定義し、その中でStepperの色を指定することができます。

以下のコードは、プライマリカラーを赤色に設定してStepperの色を変更する一例です。

MaterialApp(
  theme: ThemeData(
    primaryColor: Colors.red,
  ),
  home: YourWidget(),
)

これにより、アプリ全体のプライマリカラーが赤色に設定され、それがStepperにも適用されます。

Stepperのアイコン画像の変更

Stepperのアイコン画像の変更も容易に行うことができます。これは、各ステップの状態を表現するために使われ、ステップがアクティブ、非アクティブ、または完了状態によって異なるアイコンを表示することができます。

StepperのアイコンはStepウィジェットのstateプロパティを使用してカスタマイズすることができます。以下に、それぞれのステップの状態に応じて異なるアイコンを設定する例を示します。

Step(
  title: Text('Step 1'),
  content: Text('This is the first step'),
  state: StepState.indexed,
),
Step(
  title: Text('Step 2'),
  content: Text('This is the second step'),
  state: StepState.editing, 
),
Step(
  title: Text('Step 3'),
  content: Text('This is the third step'),
  state: StepState.complete, 
),

こうした設定により、Stepperは非常にカスタマイズが可能で、アプリケーションの見た目やユーザー体験を向上させる効果的なツールとなります。

選択ボタンの設定

「Continue」ボタンと「Cancel」ボタンがデフォルトで表示されます。全てのステップの下に表示される共通項目をカスタマイズしたい場合は、controlsBuilderプロパティを設定します。

Stepper(
  controlsBuilder: (BuildContext context, ControlsDetails details) {
    return Row(
      children: <Widget>[
        FilledButton(
          onPressed: details.onStepContinue,
          child: const Text('CONTINUE'),
        ),
        const SizedBox(width: 32),
        FilledButton(
          onPressed: details.onStepCancel,
          child: const Text('CANCEL'),
        ),
      ],
    );
  },
);

また、共通の項目を非表示にしたい場合は以下のように設定します。

controlsBuilder: (_, __) => Container()

Stepperを活用した具体的な事例

Stepperを使用したフォーム作成の例

Stepperはユーザーが複雑なフォームを順序立てて入力することを助けるための有効なツールであることが認識されています。特に、多くのフィールドまたは複雑なユーザー入力が必要な場合、Stepperはユーザーにとっての負担を軽減し、その結果、フォームの完成率を高めることが期待できます。

Flutterにおいては、Stepperウィジェットとそのstepsプロパティを使用して、ステップごとの入力フィールドを設定することができます。以下に基本的なコードを示します。

Stepper(
  steps: [
    Step(
      title: Text('Step 1'),
      content: TextFormField(
        decoration: InputDecoration(labelText: 'Enter your name'),
      ),
    ),
    Step(
      title: Text('Step 2'),
      content: TextFormField(
        decoration: InputDecoration(labelText: 'Enter your email'),
      ),
    ),
  ],
)

この例では、最初のステップでユーザーに名前を入力させ、次のステップでメールアドレスを入力させています。

Stepperを用いたオンボーディングフローの例

オンボーディングフローはアプリケーションの初回使用者がその機能を理解するのを助ける手段であり、Stepperはこのプロセスを効率的に実装するのに役立ちます。ユーザーは一つ一つのステップを追って学習し、それぞれのステップが終了するとその進行状況が視覚的に表示されます。

以下のコードは、オンボーディングフローでStepperを使用する基本的な例を示しています。

Stepper(
 type: StepperType.horizontal,
  steps: [
    Step(
      title: Text('Step 1'),
      content: Text('Welcome to our application!'),
    ),
    Step(
      title: Text('Step 2'),
      content: Text('Here is how to use feature A...'),
    ),
    Step(
      title: Text('Step 3'),
      content: Text('Here is how to use feature B...'),
    ),
  ],
)

この例では、各ステップで新しい機能の使い方をユーザーに説明しています。Stepperを使用することで、ユーザーは自分が学習プロセスのどこに位置しているかを容易に把握することができます。これにより、アプリケーションの初回利用者が混乱することなく、必要な情報を順序立てて学習すること

Stepperを利用するためのパッケージ

im_stepperパッケージの紹介

一つ目に紹介するのはim_stepperパッケージです。このパッケージはStepperのカスタマイズに非常に便利で、特にデザイン面での多様性を求めている開発者におすすめです。ボタンの形状、色、アイコンなどを自由にカスタマイズできます。

easy_stepperパッケージの紹介

もう一つ、easy_stepperパッケージもStepperの実装に役立つパッケージとして広く使用されています。このパッケージの特長はその名の通り、Stepperを簡単に実装できることです。標準的なStepperの設定だけでなく、ボタンのラベルをカスタマイズしたり、ステップの変更を検知するコールバックを設定することも可能です。

どちらのパッケージも公式ドキュメンテーションが提供されており、詳細な設定や使用方法を確認することができます。プロジェクトの要件に合わせて、スタイルを変更させることができます。

Q&A

Q1: Stepperとは何でしょうか?

Stepperはユーザーが特定のタスクを順序立てて進めるためのユーザーインターフェースコンポーネントです。それぞれのステップは、特定の情報やタスクを含みます。ステップは水平または垂直に配置することが可能で、各ステップの間には進捗状況を示すアイコンや線が通常表示されます。

Q2: FlutterでStepperをカスタマイズするにはどうすればいいですか?

FlutterのStepperウィジェットは、色やアイコン画像などのカスタマイズを許容します。具体的なカスタマイズ方法は、使用しているStepperウィジェットのプロパティを変更することで行います。たとえば、controlsBuilderプロパティを使用してステップのコントロールをカスタマイズしたり、typeプロパティを用いてStepperの表示方向を制御することが可能です。

Q3: Stepperをより効果的に使用するためのパッケージは何がありますか?

im_steppereasy_stepperなどのパッケージは、FlutterでStepperをより効果的に使用するためのオプションを提供します。これらのパッケージは、さまざまなスタイルや動作のカスタマイズを提供し、特定の用途にStepperを適応させることを容易にします。

まとめ

Stepperは順序立てて情報を伝達するのに非常に有用なUIコンポーネントで、特に多段階のフォームの作成やアプリのオンボーディングなどによく用いられます。水平または垂直の二つの形式があり、フレキシブルにステップを設定できます。FlutterではStepperウィジェットを使用して、手軽にStepperを実装することができます。そのカスタマイズは様々で、ステップの色やアイコン画像の変更などが可能です。さらに、im_stepperやeasy_stepperといったパッケージを利用することで、より多様なカスタマイズや便利な機能を活用できます。これらの知識を活用して、より効果的なUIを作成することができました。

参考

ソース(main.dartにコピペして動作確認用)

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        useMaterial3: true,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Stepper Demo'),
        ),
        body: StepperSample(),
      ),
    );
  }
}

class StepperSample extends StatefulWidget {
  @override
  _StepperSampleState createState() => _StepperSampleState();
}

class _StepperSampleState extends State<StepperSample> {
  int _currentStep = 0;

  static const List<Step> _steps = [
    Step(
        title: Text('Step One'),
        subtitle: Text('subtitle1'),
        content: Text('This is the first step'),
        isActive: true,
        state: StepState.indexed,
        label: Text('showedWhenHorizontal')),
    Step(
      title: Text('Step Two'),
      content: Text('This is the second step'),
      isActive: true,
      state: StepState.indexed,
    ),
    Step(
      title: Text('Step Three'),
      content: Text('This is the third step'),
      isActive: true,
      state: StepState.indexed,
    ),
    Step(
      title: Text('isActive:false'),
      content: Text(''),
      isActive: false,
      state: StepState.indexed,
    ),
    Step(
      title: Text('complete'),
      content: Text(''),
      state: StepState.complete,
    ),
    Step(
      title: Text('error'),
      content: Text(''),
      state: StepState.error,
    ),
    Step(
      title: Text('disabled'),
      content: Text(''),
      state: StepState.disabled,
    ),
    Step(
      title: Text('editing'),
      content: Text(''),
      state: StepState.editing,
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Stepper(
      steps: _steps,
      currentStep: this._currentStep,
      type: StepperType.vertical, // Horizontal or Vertical Stepper
      onStepTapped: (step) {
        setState(() {
          _currentStep = step;
        });
      },
      onStepContinue: () {
        setState(() {
          _currentStep = _currentStep + 1;
        });
      },
      onStepCancel: () {
        setState(() {
          _currentStep = _currentStep - 1;
        });
      },
      controlsBuilder: (BuildContext context, ControlsDetails details) {
        return Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            Visibility(
              visible: details.stepIndex != 0,
              child: FilledButton(
                onPressed: details.onStepCancel,
                child: const Text('CANCEL'),
              ),
            ),
            Visibility(
              visible: details.stepIndex < _steps.length - 1,
              child: FilledButton(
                onPressed: details.onStepContinue,
                child: const Text('CONTINUE'),
              ),
            ),
          ],
        );
      },
    );
  }
}