【Flutter】ToggleButtons使いこなし!多選択UIの効果的活用

対象者

  • Flutterを使用した開発経験があるが、ToggleButtonsの使用方法やカスタマイズ方法について詳しく知りたい方。
  • UIの使いやすさや体験を改善するための新しい手法を模索しているモバイルアプリ開発者。
  • 自身のスキルセットを拡大し、より多くのプロジェクトや課題に対応できるようにしたいと考えているプログラマー。

はじめに

モバイルアプリの開発において、そのユーザビリティや体験を高めるためのインターフェースは重要な要素です。一つの方法として、ToggleButtonsの利用があります。ToggleButtonsは一見シンプルなウィジェットの一つですが、適切に使いこなせばユーザの選択肢を直感的に示すことができ、操作性を大幅に向上させることが可能です。

しかし、はじめてToggleButtonsを使うとき、その使い方やカスタマイズ方法、状態管理についてどのように学び、理解していいのか迷うこともあるでしょう。それが今日この記事を開いたきっかけかもしれませんね。

ToggleButtons というのは、日本語で「トグルボタン」という意味です。プログラムの世界では一般的に「選択の切り替え」を可能にするボタンのグループということを示します。
Flutterにおいては、ToggleButtonsは一連のオプションからユーザーが複数の選択を行えるウィジェットです。そのため、ユーザーに複数の選択肢を提示し、その中から一つ以上を選択させることができます。
実際のアプリとしては、オンラインの商品購入画面で、商品の色やサイズなどを選択するケースにToggleButtonsを利用し、ユーザーが複数のオプションから選択するというような機能を実現することができます。

本記事では、ToggleButtonsの基本的な使い方から、色や見た目のカスタマイズ方法、さらには複数のToggleButtonsとの連携といった高度な利用ケースについて詳しく説明しています。そして、よくある問題や落とし穴、その解決策もご紹介します。
この記事を読むことで、FlutterでのToggleButtonsの使い方についてより深い理解を得ることができます。そしてあなたの開発スキルがさらに一段階レベルアップすることでしょう。それでは、一緒にToggleButtonsの世界を探求してみましょう。

ToggleButtonsの基本

ToggleButtonsとは、Flutterのウィジェットの一つで、複数のボタンを一つのグループとして管理する機能を提供します。このウィジェットは、一つ以上のボタンが選択された状態を維持することができ、それぞれのボタンの選択状態は独立して変更できます。具体的には、isSelectedというプロパティを通じて各ボタンの選択状態を制御することが可能です。

なぜToggleButtonsを使用するのでしょうか?その答えは、ユーザーエクスペリエンスの向上とコードの整理にあります。一連の関連するアクションを一つのグループにまとめることで、ユーザーにとっての選択の視覚的な整理と、開発者にとっての状態管理の効率化を図ることができます。したがって、ToggleButtonsはインタラクティブなUIを作成するための重要なツールと言えるでしょう。

ToggleButtonsの使用方法

ToggleButtonsは、その利便性と柔軟性から、多くのFlutter開発者に利用されています。ここではその基本的な設定方法から、具体的な状態制御、そしてボタンタップの取り扱いについて詳しく解説します。

ToggleButtonsの設定方法

まず、基本的なToggleButtonsの設定方法から説明します。ToggleButtonsウィジェットは主に二つの必須のプロパティ、childrenisSelectedを持っています。childrenプロパティには表示したいボタンのウィジェットのリストを、そしてisSelectedにはそれぞれのボタンの選択状態を表すbool値のリストを設定します。

以下に、三つのIconButtonを持つToggleButtonsの設定例を示します:

ToggleButtons(
  children: <Widget>[
    Icon(Icons.terrain),
    Icon(Icons.light_mode),
    Icon(Icons.nightlife),
  ],
  isSelected: [false, false, false],
);

このように、childrenプロパティにウィジェットのリストを、isSelectedプロパティに選択状態のリストを与えることでToggleButtonsは設定できます。
上記のコードでは、isSelectedリストはfalse値で初期化され、その結果、初期状態では全てのボタンが非選択状態となります。

ボタンタップの取り扱い

FlutterのToggleButtonsウィジェットでは、ボタンがタップされたときの振る舞いをカスタマイズすることが可能です。これは、onPressed パラメータを通じて実現されます。onPressed には、ボタンがタップされたときに呼び出される関数を指定します。この関数は一つのパラメータを取ります。これは、タップされたボタンのインデックスです。

実装の根拠としては、ユーザーとのインタラクションを取り扱うための方法として一般的に利用されています。これにより、あるボタンがタップされたときに何が起こるべきかを具体的に制御できます。それにより、アプリケーションのUXを向上させ、特定のアクションに応じた動作を行うことができます。

例えば、以下のコードスニペットは、ToggleButtonsのonPressed パラメータを利用して、タップされたボタンの状態を更新する方法を示しています:

List<bool> _isSelected = [false, false, false];

ToggleButtons(
  isSelected: _isSelected,
  children: <Widget>[
    Icon(Icons.ac_unit),
    Icon(Icons.call),
    Icon(Icons.cake),
  ],
  onPressed: (int index) {
    setState(() {
      _isSelected[index] = !_isSelected[index];
    });
  },
)

この例では、各ボタンがタップされると、そのボタンの選択状態が反転します。こうした対話的なアクションは、ユーザーがアプリケーションとの対話を通じて情報を反映・制御できるようにするために不可欠です。

結論として、FlutterのToggleButtonsウィジェットはその柔軟性と強力なカスタマイズ機能を持つため、一見すると複雑に見えるかもしれませんが、ボタンタップの取り扱いなど、基本的な部分を理解すれば容易に使いこなすことができます。この振る舞いは、onPressedパラメータを適切に設定することで独自のロジックを容易に実装でき、結果としてユーザーエクスペリエンスを向上させることが可能です。

ToggleButtonsのカスタマイズ方法

ToggleButtonsはその見た目を自由にカスタマイズできる、柔軟性の高いウィジェットです。このセクションではボタンの色や見た目のカスタマイズ、renderBorderの使用法、そしてその他の色のカスタマイズについて説明します。

ボタンの色や見た目のカスタマイズ

ToggleButtonsは色や形状などの見た目をカスタマイズするための様々なプロパティを持っています。例えば、ボタンの色はcolorプロパティ、選択されているボタンの色はselectedColorプロパティを用いて設定できます。形状はrenderBorderプロパティとborderWidthプロパティを使用します。

以下に、色と形状をカスタマイズしたToggleButtonsの例を示します:

ToggleButtons(
  color: Colors.green,
  selectedColor: Colors.blue,
  borderRadius: BorderRadius.circular(8.0),
  children: <Widget>[
    Icon(Icons.terrain),
    Icon(Icons.light_mode),
    Icon(Icons.nightlife),
  ],
  isSelected: [false, false, false],
);

このコードでは、ボタンの色が緑に、選択されたボタンの色が青に設定され、ボタンの形状は角が丸い形になります。

renderBorderを使用した境界線管理

次に、境界線の管理について説明します。ToggleButtonsにはrenderBorderプロパティがあり、これを用いることでボタンの境界線の表示・非表示を管理できます。renderBorderプロパティはbool値を取り、trueの場合は境界線を表示し、falseの場合は非表示とします。

以下に、renderBorderを使用したToggleButtonsの例を示します:

ToggleButtons(
  renderBorder: false,
  children: <Widget>[
    Icon(Icons.terrain),
    Icon(Icons.light_mode),
    Icon(Icons.nightlife),
  ],
  isSelected: [false, false, false],
);

このコードでは、renderBorderプロパティがfalseに設定されているため、ボタンの境界線は表示されません。

色のカスタマイズのまとめ

ToggleButtonsウィジェットは、その柔軟性からカスタマイズの幅が非常に広いです。特に色のカスタマイズに関しては、非常に多くのプロパティを利用することができます。
以下に、ToggleButtonsウィジェットのさらなる色に関するプロパティを使った例を示します:

ToggleButtons(
  color: Colors.green,
  selectedColor: Colors.white,
  disabledColor: Colors.grey,
  fillColor: Colors.blue,
  highlightColor: Colors.yellow,
  splashColor: Colors.red,
  children: <Widget>[
    Icon(Icons.ac_unit),
    Icon(Icons.call),
    Icon(Icons.cake),
  ],
  onPressed: (int index) {
    setState(() {
      _isSelected[index] = !_isSelected[index];
    });
  },
)

このコードでは、各プロパティがどのようにToggleButtonsの見た目を変えるかを示しています。colorは通常状態のアイコンの色を、selectedColorは選択されたアイコンの色を、disabledColorは無効化されたアイコンの色を変更します。また、fillColorは選択されたボタンの背景色を、highlightColorはボタンが押されている間の色を、splashColorはボタンが押された時のインクスプラッシュ効果の色を変えます。

結論として、色のカスタマイズはユーザーエクスペリエンスを向上させ、アプリケーションをより直感的に操作することを可能にします。それぞれのプロパティを適切に使用することで、アプリケーションの見た目をユーザーの要求に応じて変えることが可能です。

以下に、「ToggleButtonsの実際の使用例」のセクションを記述します:

ToggleButtonsの実際の使用例

ToggleButtonsウィジェットは、アプリケーションのUIにおいて選択可能なオプションを提供するための非常に強力なツールです。シンプルな例から高度な利用ケースまで、その応用範囲は広大です。

ToggleButtonsを使ったシンプルな例

まず初めに、シンプルなToggleButtonsの例を見てみましょう。この例では、3つのアイコンから選択するためのToggleButtonsを設定します。

ToggleButtons(
  children: <Widget>[
    Icon(Icons.icecream),
    Icon(Icons.cake),
    Icon(Icons.candy),
  ],
  onPressed: (int index) {
    setState(() {
      for (int buttonIndex = 0; buttonIndex < isSelected.length; buttonIndex++) {
        if (buttonIndex == index) {
          isSelected[buttonIndex] = !isSelected[buttonIndex];
        } else {
          isSelected[buttonIndex] = false;
        }
      }
    });
  },
  isSelected: isSelected,
);

このコードでは、アイスクリーム、ケーキ、キャンディのアイコンを表示する3つのボタンが設定されています。各ボタンを押すと、そのボタンだけが選択状態になり、他のボタンは非選択状態になります。これは、選択したアイテムを一つだけに制限する場面において有用です。

ToggleButtonsの高度な利用ケース

次に、少し複雑な例を見てみましょう。この例では、各ボタンに異なる色を設定し、選択した色に応じて背景色を変更するアプリケーションを作ります。

Color backgroundColor = Colors.white;

ToggleButtons(
  fillColor: Colors.grey,
  children: <Widget>[
    Icon(Icons.red),
    Icon(Icons.green),
    Icon(Icons.blue),
  ],
  onPressed: (int index) {
    setState(() {
      for (int buttonIndex = 0; buttonIndex < isSelected.length; buttonIndex++) {
        isSelected[buttonIndex] = buttonIndex == index;
      }
      backgroundColor = isSelected[0] ? Colors.red : isSelected[1] ? Colors.green : Colors.blue;
    });
  },
  isSelected: isSelected,
);

// 各種ウィジェットが配置されたウィジェットツリー
Container(
  color: backgroundColor,
  child: ...
);

この例では、色選択のToggleButtonsを使っています。各ボタンを押すと、背景色がその色に変更されます。こうした高度な利用ケースを通じて、ToggleButtonsはその強力なカスタマイズ性と柔軟性を確認することができます。

ToggleButtonsでよくある問題と解決策

ToggleButtonsは非常に便利で強力なウィジェットですが、初めて使う方や経験の少ない方は一部で課題を感じるかもしれません。ここではよくある問題とその解決策を紹介します。

isSelectedプロパティの初期化忘れ

ToggleButtonsを使用する際の一般的な落とし穴の一つは、isSelectedプロパティの初期化を忘れることです。isSelectedはToggleButtonsウィジェットが内部的に選択状態を追跡するために使用します。各ボタンの選択状態を格納するbool値のリストでなければなりません。そのため、ToggleButtonsウィジェットを作成する際には必ずこのリストを初期化し、正確な数のbool値を持っていることを確認しましょう。

nPressedコールバック内で状態更新を忘れ

もう一つのよくある問題は、onPressedコールバック内で状態の更新を忘れることです。選択されたボタンの状態を正確に追跡するためには、onPressedコールバック内でsetStateメソッドを適切に使用することが重要です。

Q&A

Q: ToggleButtonsのisSelectedプロパティは何をするためのものでしょうか?

A: isSelectedプロパティは、それぞれのボタンの選択状態を制御するために使用します。このプロパティには、ボタンの数と同じ長さの真偽値リストを提供します。これにより、各ボタンが現在選択されているかどうかを示すことができます。

Q: childrenプロパティについて説明していただけますか?

A: childrenプロパティは、ToggleButtonsの各ボタンの見た目と動作を制御するために使用します。これはウィジェットのリストで、各ウィジェットは対応するボタンの外観と動作を定義します。

Q: ToggleButtonsでよく遭遇する問題や注意点は何ですか?

A: ToggleButtonsを使用する際には、選択状態の制御やボタンの外観のカスタマイズに注意が必要です。特に、isSelectedリストの長さがchildrenプロパティのウィジェットの数と一致していることを確認することが重要です。また、各ボタンのタップハンドラ内で状態を適切に更新することも、良いユーザーエクスペリエンスを提供するために必要です。

まとめ

私たちはFlutterのToggleButtonsの多様な特性について学びました。ToggleButtonはユーザーに複数の選択肢を提示し、それぞれの選択状態を制御するウィジェットです。その存在はUIの選択肢を効率的に提示し、ユーザーとのインタラクションを向上させるために不可欠です。

また、それぞれのToggleButtonsの使用方法と状態管理、さらにそのカスタマイズ方法も見てきました。その中でも特にisSelectedプロパティを使って選択状態を制御し、子ウィジェットのリストを作成するchildrenプロパティの使用は理解を深めました。

さらに、ToggleButtonsの実際の使用例を通じて、シンプルな利用から高度な利用ケースまで確認しました。そして、よくある問題やその解決策を検討し、学習リソースを提供することで、より深い理解を得ることができました。

参考

ソース(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: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<bool> _selections1 = List.generate(3, (_) => false);
  List<bool> _selections2 = List.generate(3, (_) => false);
  List<bool> _selections3 = [true, false, false];

  List<Color> _colorList = [Colors.red, Colors.green, Colors.blue];
  Color _backgroundColor = Colors.red;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter ToggleButtons Example'),
      ),
      body: Center(
        child: Column(
          children: [
            ToggleButtons(
              borderColor: Colors.blue,
              fillColor: Colors.lightBlue,
              borderWidth: 2,
              selectedBorderColor: Colors.blue,
              selectedColor: Colors.white,
              borderRadius: BorderRadius.circular(8),
              children: <Widget>[
                Icon(Icons.access_alarm),
                Icon(Icons.weekend),
                Icon(Icons.cake),
              ],
              onPressed: (int index) {
                setState(() {
                  _selections1[index] = !_selections1[index];
                });
              },
              isSelected: _selections1,
            ),
            ToggleButtons(
              color: Colors.green,
              selectedColor: Colors.white,
              disabledColor: Colors.grey,
              fillColor: Colors.blue,
              highlightColor: Colors.yellow,
              splashColor: Colors.red,
              children: <Widget>[
                Icon(Icons.ac_unit),
                Icon(Icons.call),
                Icon(Icons.cake),
              ],
              onPressed: (int index) {
                setState(() {
                  _selections2[index] = !_selections2[index];
                });
              },
              isSelected: _selections2,
            ),
            Container(
              color: _backgroundColor,
              padding: EdgeInsets.all(8),
              child: ToggleButtons(
                fillColor: Colors.grey,
                children: <Widget>[
                  Text('R'),
                  Text('G'),
                  Text('B'),
                ],
                onPressed: (int selectedIndex) {
                  final list =
                      List.generate(3, (index) => index == selectedIndex)
                          .toList();
                  setState(() {
                    _selections3 = list;
                    _backgroundColor = _colorList[selectedIndex];
                  });
                },
                isSelected: _selections3,
              ),
            ),
          ],
        ),
      ),
    );
  }
}