以下のスクリーンショットのように、ユーザーに複数の選択肢の中から一つを選んでもらう際にRadioボタンを作成したいケースがある。
このようなケースではRadio
ウィジェットを使うと簡単に作成できる。
本エントリではRadio
を用いたシンプルなRadioボタンの作成方法を説明する。
Radioウィジェットとは
Radio
ウィジェットはMaterial DesignのRadio Buttonsを実装するためのクラス。
上記リンクでも説明されている通り、単独ではなくListTile
ウィジェットと合わせて使うことが多い。
アプリの設定画面などで使用頻度の高いウィジェットで、選択された値は
provider
などを用いてアプリ内でシェアするといった使い方もある。
(light / dark テーマの設定など)
Radioボタンの作成方法
次のスクリーンショットのようなサンプルアプリを作成して説明する。
選択した値をText
で表示するというシンプルなアプリ。
では作り方を説明する。
1. 選択値用の変数作成
Radio
ウィジェットで選択した値を格納する変数を用意する。
int _currentValue = 1;
2. RadioウィジェットをListTileウィジェットでラップ
上述した通り、Radio
ウィジェットはListTile
ウィジェットと合わせて使うことが多い。
各選択肢を次のように記述する。
ListTile( title: Text("1"), leading: Radio<int>( value: 1, groupValue: _currentValue, onChanged: (val) { setState(() { _currentValue = val ?? 1; }); }), ),
上記のコードでRadioボタンが一つできる。
これを選択肢の数だけ作成する。ポイントはgroupValue
を揃えること。
これで同じグループに属したRadioボタンであることがわかる。
逆に異なるグループであればgroupValue
は異なる変数を渡す必要がある。
value
プロパティはかく選択肢に割り振りたい値を渡す。
文字列でも数値でもよい。
またonChanged
には、選択された際の処理をコールバック形式で記述する。
引数にはRadio
ウィジェットのvalue
が渡されるので、setState()
で状態を更新する。
ListTile
を3つに増やすと次の様になる。
ListTile( title: Text("1"), leading: Radio<int>( value: 1, groupValue: _currentValue, onChanged: (val) { setState(() { _currentValue = val ?? 1; }); }), ), ListTile( title: Text("2"), leading: Radio<int>( value: 2, groupValue: _currentValue, onChanged: (val) { setState(() { _currentValue = val ?? 2; }); }), ), ListTile( title: Text("3"), leading: Radio<int>( value: 3, groupValue: _currentValue, onChanged: (val) { setState(() { _currentValue = val ?? 3; }); }), ),
この記述でRadioボタンが3つ作成できる。
3. Radioウィジェットで選択した値を表示する
選択した値が格納されている_currentValue
を表示する。
Text( "Selected Number: $_currentValue", style: TextStyle(fontSize: 24, fontWeight: FontWeight.w800),
あとはデザインを少し整えて冒頭のgif画像の様なアプリができる。
最終的なコードは次の様になる。
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'radio group app', theme: ThemeData( primarySwatch: Colors.blue, ), home: HomeWidget()); } } class HomeWidget extends StatefulWidget { const HomeWidget({Key? key}) : super(key: key); @override State<HomeWidget> createState() => _HomeWidgetState(); } class _HomeWidgetState extends State<HomeWidget> { int _currentValue = 1; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Radio Example App")), body: SafeArea( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Select Number", style: TextStyle(fontSize: 24, fontWeight: FontWeight.w800), ), ListTile( title: Text("1"), leading: Radio<int>( value: 1, groupValue: _currentValue, onChanged: (val) { setState(() { _currentValue = val ?? 1; }); }), ), ListTile( title: Text("2"), leading: Radio<int>( value: 2, groupValue: _currentValue, onChanged: (val) { setState(() { _currentValue = val ?? 1; }); }), ), ListTile( title: Text("3"), leading: Radio<int>( value: 3, groupValue: _currentValue, onChanged: (val) { setState(() { _currentValue = val ?? 3; }); }), ), SizedBox( height: 16, ), Text( "Selected Number: $_currentValue", style: TextStyle(fontSize: 24, fontWeight: FontWeight.w800), ), ], )), ), ); } }