[Flutter/dart] CheckboxListTileをタップ時のイベントを実装したい
概要
文字列とチェックボックスを横一列に配置したい場合はCheckboxListTileが便利です。
しかし、文字列をタップしたときに、別のページへ移動するなどのイベントを実装したい場合は注意が必要です。
class MyHomePageState extends State<MyHomePage> {
List<int> list=List.generate(5, (index) => index);
List<bool> values=List.generate(5, (index) => false);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('demo'),
),
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
children: list.map((e) =>
CheckboxListTile( //これ!
value: values[e],
title: Text(
"${e}",
style: TextStyle(
fontSize: 18
),
),
onChanged: (value){
values[e]=value;
setState(() {});
}
)
).toList(),
)
)
);
}
}

問題点
CheckboxListTileにはonChangedという、チェックボックス変更時の動作を規定するプロパティがあります。チェックボックスの表示を変えたりする動作はここに実装します。
しかし、先にも述べた通り、CheckboxListTileをタップしたときに(チェック値の変更とは別の)イベントを追加したい場合は注意が必要です。
そもそもCheckboxListTileにはonTapは定義されておらず、GesutureDetectorでラップしても、タップ時にはonChangedイベントが走ってしまいます。
解決策
自力で実装しましょう。
ListTileのtrailingにCheckboxを割り当てます。
ListTileの場合は全体のonTapとtrailingのontap(onChanged)は別々に認識してくれます。
class MyCheckboxListTile extends StatefulWidget{
Widget leading;
Widget title;
Function onTap;
Function(bool) onCheckChanged;
MyCheckboxListTile({this.leading, this.title, this.onTap, this.onCheckChanged});
@override
State<StatefulWidget> createState() {
return MyCheckboxListTileState();
}
}
class MyCheckboxListTileState extends State<MyCheckboxListTile>{
bool value=false;
@override
Widget build(BuildContext context) {
return ListTile(
leading: widget.leading,
title: widget.title,
trailing: Checkbox(
value: value,
onChanged: (value){
this.value=value;
widget.onCheckChanged(value);
setState(() {});
},
),
onTap: widget.onTap,
);
}
}
class MyPage extends StatelessWidget{
List<int> list=List.generate(5, (index) => index);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('demo'),
),
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
children: list.map((e) =>
MyCheckboxListTile( //ここで使う!
title: Text(
"${e}",
style: TextStyle(
fontSize: 18
),
),
onTap: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (context)=>SomePage()
)
);
},
onCheckChanged: (value){},
)
).toList()
)
)
);
}
}
タイルの1つ1つがStatefulWidgetになっているので、チェック時に該当タイルだけをリビルドすれば済みます。

結論
onTapをonChangedと別で実装したい場合はListTileを使って自力で実装しましょう。
最新記事
すべて表示現象 あるアイコンは長押し時に所定の動作を実行します これを実現するために、GestureDetectorのonLongPressに処理を登録していました しかしいざビルドしてみると、アイコンが表示されたタイミングで処理が実行されてしまいました 以下が該当部分のソースコードです。 さあ、どこが間違っているでしょう? return GestureDetector( child: Containe
前提 以下のようなケースを考えます。 アイテムの一覧がある ある1つのアイテムの詳細を表示するページがある 詳細ページではそのアイテムの削除ができる 削除したら他のページ(一覧ページなど)に戻る これはアプリではよくあるパターンだと思います。 課題 reduxパターンを用いている、より具体的にはProviderで状態を管理している場合、以下のような構成になっているのではないでしょうか? アプリ全体
やりたいこと Reduxで状態管理をする。状態はAppStateとする。 アプリ開始時にリモートのデータベースからデータの取得を開始 データを取得 取得中は待機マークを表示 取得したデータからAppStateを作成 作成したAppStateを元にUIを描画 方法 3、4、5を実現するためには、「取得完了」のフラグをAppStateに追加しましょう(※1)。 ビューはこのフラグを見て表示を切り替えま