【Flutter】カスタムラジオボタンを作成する方法〔実装イメージvideo付き!〕

Flutter
 

Flutterでカスタムラジオボタン(CustomRadioButton)を作成しました。

実装ソースとそのソースがどういう意味を持っているかを説明していきます。

実装イメージ

以下のようなボタンがありつつも、それらはラジオボタン的な感じで一つしか選択できないような
Widgetを作成する。

実装ソース

以下のようなWidgetを作成することで実装できます。

実装ポイントは3つです。

  • 選択したボタンのIndexを保持するStateを作成する
  • 作成したボタンをList.generateで配置する
  • 選択されているボタンの色を変える

それぞれを赤・青・黄でハイライトしました。

以下にて詳細の実装について説明していきます。

class CustomRadioButton extends StatefulWidget {
  const CustomRadioButton({Key? key}) : super(key: key);

  @override
  State<CustomRadioButton> createState() => _CustomRadioButtonState();
}

class _CustomRadioButtonState extends State<CustomRadioButton> {
  int? _selectedValueIndex;
  List<String> buttonText = ['今 週', '来 週', '2週間後', 'それ以降'];

  Widget button({required String text, required int index}) {
    return InkWell(
      splashColor: Colors.cyanAccent,
      onTap: () {
        setState(() {
          _selectedValueIndex = index;
        });
      },
      child: Container(
        padding: const EdgeInsets.all(12),
        color: index == _selectedValueIndex ? Colors.blue : Colors.white,
        child: Text(
          text,
          style: TextStyle(
            color: index == _selectedValueIndex ? Colors.white : Colors.black,
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        ...List.generate(
          buttonText.length,
          (index) => button(
            index: index,
            text: buttonText[index],
          ),
        ),
      ],
    );
  }
}

選択したボタンのIndexを保持するStateを作成する

Widget内の動的な変数を保持しておくためにはStatefulWidgetを定義してあげることが必要です。

StatefulWidgetの理解はこちらからよかったら!↓

次に、indexを保持するためにローカル変数を定義します。
(_selectedValueIndex)

最後に、ボタン(InkWell)をタップしたときは引数のindexを_selectedValueIndexに書き換えるように
ソースを記述しておきます。(buttonは未定義なので、この時点ではエラー)

class CustomRadioButton extends StatefulWidget {
  const CustomRadioButton({Key? key}) : super(key: key);

  @override
  State<CustomRadioButton> createState() => _CustomRadioButtonState();
}

class _CustomRadioButtonState extends State<CustomRadioButton> {
  int? _selectedValueIndex;
  List<String> buttonText = ['今 週', '来 週', '2週間後', 'それ以降'];

  Widget button({required String text, required int index}) {
    return InkWell(
      splashColor: Colors.cyanAccent,
      onTap: () {
        setState(() {
          _selectedValueIndex = index;
        });
      },
    (略)

作成したボタンをList.generateで配置する

一つ一つのWidgetにてindex,textというローカル変数が定義されており、
それぞれにてボタンをタップしたときに各インデックスの値が_selectedValueIndexというCustomRadioButtonのWidgetにて持つ変数に保持されているというイメージです。
indexという変数には0,1,2,3というように値を持っていると思われます。
(indexの長さはbuttonTextの配列の長さです)

補足ですが、Listの前についている「…」は配列を展開するという意味です。
children内に一つ一つの要素を展開すると言うイメージです。
(つくづくjsと似てるなぁと…)

class CustomRadioButton extends StatefulWidget {
  const CustomRadioButton({Key? key}) : super(key: key);

  @override
  State<CustomRadioButton> createState() => _CustomRadioButtonState();
}

class _CustomRadioButtonState extends State<CustomRadioButton> {
  int? _selectedValueIndex;
  List<String> buttonText = ['今 週', '来 週', '2週間後', 'それ以降'];
(略)

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        ...List.generate(
          buttonText.length,
          (index) => button(
            index: index,
            text: buttonText[index],
          ),
        ),
      ],
    );
  }
}

選択されているボタンの色を変える

選択されたボタンは_selectedValueIndexにて動的に管理されており、
その値と各buttonメソッドのindex変数の値と同じならば選択されているということになるため、
そのボタンのStyleを変えてあげるイメージです。

以下のソースでは、選択されたタイミングでボタンの色とテキストの色を変えています。

補足ですが、『index == _selectedValueIndex ? Colors.blue : Colors.white』は
三項演算子の記述方法となります。
index == _selectedValueIndexという条件式がTrueならばColors.blueにするし、
FalseならばColors.whiteにするということです。

class CustomRadioButton extends StatefulWidget {
  const CustomRadioButton({Key? key}) : super(key: key);

  @override
  State<CustomRadioButton> createState() => _CustomRadioButtonState();
}

class _CustomRadioButtonState extends State<CustomRadioButton> {
  int? _selectedValueIndex;
  List<String> buttonText = ['今 週', '来 週', '2週間後', 'それ以降'];

  Widget button({required String text, required int index}) {
    return InkWell(
      splashColor: Colors.cyanAccent,
      onTap: () {
        setState(() {
          _selectedValueIndex = index;
        });
      },
      child: Container(
        padding: const EdgeInsets.all(12),
        color: index == _selectedValueIndex ? Colors.blue : Colors.white,
        child: Text(
          text,
          style: TextStyle(
            color: index == _selectedValueIndex ? Colors.white : Colors.black,
          ),
        ),
      ),
    );
  }

(略)

コメント

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