ラジオボタンは、複数の選択肢の中から1つのアイテムを選択(単一選択・排他的選択)できるボタンです。
この記事では、FlutterのRadioListTile()
を使ったラジオボタンの作り方を解説します。
RadioListTile()
で使う変数は、int型で指定するのがわかりやすい方法ですが、より実践的に使うためにenum型を使う方法と、enum型を使うメリットも紹介します。
- Flutter : 3.27.1
- Dart : 3.6.0
\\ChoiceChipを使う選択ボタンはこちら//

基本のラジオボタン

RadioListTile()
一般的にラジオボタンは、ボタンとテキストを組み合わせて作ることが多いので、Flutterでは、この2つをセットにして扱えるウィジェットRadioListTile()
を使うのが一番簡単です。
RadioListTile
で使う代表的なプロパティは、次の4つです。
title:
ボタンの横に表示する文字列など(ウィジェットで指定する)value:
このボタンに割り当てる値(int型の数値指定が簡単)groupValue:
選択肢の中で選ばれている値(value:
と同じ型の変数を用意する)onChanged:
ボタンがクリックされたときの処理
int _radioValue = 1;
RadioListTile(
title: Text('選択肢 1'),
value: 1,
groupValue: _radioValue,
onChanged: (int? value) {
setState(() {
_radioValue = value!;
});},
),
上記のRadioListTile()
一つが、ラジオボタンの一つ分です。
ボタンが押されたときに実行されるonChanged:
では、setState()
の中でgroupValue:
に指定した変数を更新して、画面を再描画します。
選択肢を複数個並べるときは、このRadioListTile()
をColumn()
で包みます。
複数の選択肢を作るときは、value: 1,
の部分を、value: 2,
、value: 3,
のように別の番号を指定します。
ボタンだけ表示したいときは、テキスト部分のないRadio()
ウィジェットを使ってもいいですが、RadioListTile
のtitle:
プロパティを書かなければボタンだけが表示されます。
title:
プロパティは、必須プロパティではありません。
RadioListTile()の実装:3ステップ

class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _radioValue = 1;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
// 1つめのボタン
RadioListTile(
title: Text('選択肢 1'),
value: 1,
groupValue: _radioValue,
onChanged: (int? value) => _onRadioSelected(value),
),
// 2つ目のボタン
RadioListTile(
title: Text('選択肢 2'),
value: 2,
groupValue: _radioValue,
onChanged: (int? value) => _onRadioSelected(value),
),
// 3つ目のボタン
RadioListTile(
title: Text('選択肢 3'),
value: 3,
groupValue: _radioValue,
onChanged: (int? value) => _onRadioSelected(value),
),
],
),
);
}
_onRadioSelected(int? value) {
setState(() {
_radioValue = value!;
});
}
}
順を追って解説します。
まず初めのポイントは、StatefulWidget
です。(行番号1)
選択結果の画面更新でsetState()
を使うには、StatefulWidget
が必要です。
次は、行番号8の変数宣言です。
class _MyHomePageState extends State<MyHomePage> {
int _radioValue = 1;
@override
Widget build(...
この変数には「どのラジオボタンが選ばれているか」という値が入ります。
ここでは、int型で_radioValue
という変数を作成して、初期値を1
にしました。
groupValue: _radioValue
としたラジオボタン群が、「排他的選択ができるボタンのグループ」になります。
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
// 1つめのボタン
RadioListTile(
title: Text('選択肢 1'),
value: 1,
groupValue: _radioValue,
onChanged: (int? value) => _onRadioSelected(value),
),
// 2つ目のボタン
RadioListTile(
title: Text('選択肢 2'),
value: 2,
groupValue: _radioValue,
onChanged: (int? value) => _onRadioSelected(value),
),
// 3つ目のボタン
RadioListTile(
title: Text('選択肢 3'),
value: 3,
groupValue: _radioValue,
...
...
RadioListTile()
のvalue:
の値は、各ボタンごとに違う値にします。
groupValue:
で指定する変数がint型なら、順番に1、2、3という感じです。(行番号19, 27, 35)
横並びにするならRow()
で包みますが、スマホの幅に収まりきらないとエラーになるので、Row()
をさらにWrap()
で包むと、入りきらないラジオボタンは次の行へ自動で送られます。
下記のChoiceChip
を使った単一選択ボタンの書き方では、Wrap()
を使った例を紹介しています。

応用:enumで選択値を管理する
選択肢が多い場合などは、RadioListTile()
の選択値をint型ではなく、自分独自のenum型を作って管理すると、あとのメンテナンスの手間の軽減が期待できます。
enum型は、日本語では「列挙型」と訳されるように、使用する値を独自に列挙しておける「型」です。
列挙する値は自分独自の単語で指定できるので、単に数値で管理するよりも直感的でわかりやすくなります。

まずは、色名を列挙しておくenumを作ります。
値は、カンマで区切って並べます。
リストに似ていますが、[ ]
ではなく{ }
で囲むことに注意です。
文末に;
は入りません。
enum RadioValue { red, blue, green }
このコードで、RadioValue
という自分独自の新しい型が作成できます。
作成したenum型で変数を作ります。
ここでは、初期画面で赤が選択されるよう、初期値にRadioEnumValue.red
を代入しました。(行番号25)
enum RadioValue { red, blue, green }
class _MyHomePageState extends State<MyHomePage> {
RadioValue _radioValue = RadioValue.red;
@override
Widget build(BuildContext context) {
return ...
RadioListTile(
title: Text("赤", style: TextStyle(color: Colors.red)),
value: RadioValue.red,
groupValue: _radioValue,
onChanged: (RadioValue? value) => _onRadioSelectedEnum(value),
),
これで、タイトルに「赤」と表示する選択肢はRadioValue.red
という値で扱えるようになります。
下記コードが、enumを使った全文です。
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
enum RadioValue { red, blue, green }
class _MyHomePageState extends State<MyHomePage> {
RadioValue _radioValue = RadioValue.red;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
SizedBox(height: 100.0),
// 1つめのボタン
RadioListTile(
title: Text("赤", style: TextStyle(color: Colors.red)),
value: RadioValue.red,
groupValue: _radioValue,
onChanged: (RadioValue? value) => _onRadioSelectedEnum(value),
),
// 2つめのボタン
RadioListTile(
title: Text("青", style: TextStyle(color: Colors.blue)),
value: RadioValue.blue,
groupValue: _radioValue,
onChanged: (RadioValue? value) => _onRadioSelectedEnum(value),
),
// 3つめのボタン
RadioListTile(
title: Text("緑", style: TextStyle(color: Colors.green)),
value: RadioValue.green,
groupValue: _radioValue,
onChanged: (RadioValue? value) => _onRadioSelectedEnum(value),
),
],
),
);
}
_onRadioSelectedEnum(RadioValue? value) {
setState(() {
_radioValue = value!;
});
}
}
enumを使うメリット・デメリット
enumは、使うのに慣れないと難しく感じます。
Flutter公式のサンプルコードでenumを使っているのを見ても、複雑な印象を受けるかもしれません。
でも、enumでRadioButtonを管理するメリットは、ちゃんとあるんです。
メリット その1
enumを使うメリットがあるケースの一つ目は、選択肢が「たくさんある」ときや、作成後に「追加削除」や「並び順の変更」が考えられるときです。

ボタンに指定するvalue: 1
のint数値は、上からカウントアップ指定する必要はありませんが、削除・追加・位置の入れ替えで番号が飛び飛びになったり欠番があると、メンテナンス時の混乱の原因になります。
メリット その2
二つ目のケースは、title:
の表示内容が「長文」だったり、テキスト表示の代わりに「アイコン」や「イメージ」を使っている場合など、内容が一目でわかりにくいときです。
こういうときは、単語1つで内容がわかるenumを使うと、「2番はなんだっけ?」といちいちタイトルのテキストを確認する必要がなくなります。

RadioListTile(
title: Text("はるはあけぼの やうやうしろく..."),
value: RadioValue.spring,
groupValue: _radioValue,
onChanged: (RadioValue? value) => _onRadioSelectedEnum(value),
),
RadioListTile(
title: Text("ふゆはつとめて ゆきのふりたるは..."),
value: RadioValue.winter,
groupValue: _radioValue,
onChanged: (RadioValue? value) => _onRadioSelectedEnum(value),
),
RadioListTile(
title: Text("あきはゆうぐれ ゆうひのさして..."),
value: RadioValue.autumn,
groupValue: _radioValue,
onChanged: (RadioValue? value) => _onRadioSelectedEnum(value),
),
RadioListTile(
title: Text("なつはよる つきのころはさらなり..."),
value: RadioValue.summer,
groupValue: _radioValue,
onChanged: (RadioValue? value) => _onRadioSelectedEnum(value),
),
メリット その3
アプリ全体で何らかのステータス管理をenumで行っていて、そのenumにラジオボタンを連動させることができるとき。
実は、これはメリットというよりも、より実践的なアプリでは必然的に導入することになる手法の一つです。
ラジオボタンで値が選択されたあとの処理は、条件ごとに処理分岐させるケースが多いので、選択値をenum型として明示して管理するとコードがわかりやすくなるのです。
デメリット
RadioListTile()
で、enumを使うデメリットがあるケースがあるとしたら、選択内容が単純でわかりやすいときだと思います。
ラジオボタンのためだけに、わざわざenumを作るのは手間が増えるだけですから、簡単な選択ボタンだけならint型で十分でしょう。
サブタイトルをつけるには
この記事の冒頭の動画で表示しているRadioListTile()
では、タイトルの下にサブタイトルを出しています。
RadioListTile()
にサブタイトルを付けるには、subtitle:
プロパティを使います。
RadioListTile(
title: Text("サブテキスト付き 1"),
subtitle: Text("選択肢1を説明"),
value: RadioEnumValue.first,
groupValue: _radioEnumValue,
onChanged: (RadioEnumValue? value) => _onRadioSelectedEnum(value),
),
コメント