[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を使って自力で実装しましょう。
最新記事
すべて表示現象 アプリ内にAdmobを追加して、アプリを起動すると、下記のエラーが発生 java.lang.RuntimeException: Unable to get provider com.google.android.gms.ads.MobileAdsInitProvider 原因 AndroidManifestの書き方が誤っていた。 <meta-data>はactivityと同じ階層にある必要が
概要 Uriを持っていて、Urlに変換したい場合の方法で少し手惑ったので共有します 方法 String url = uri.toString(); これだけです。 最後に ページを開くだけだとUriでもUrlでもいいんですが、WebViewはUrlを要求してくるんですよね。
問題 以前、日本語を含むURLを開くためには、エンコーディングしてやる必要がある、という記事を書きました。 しかし、すでにエンコーディングされているURLを再度エンコーディングしてしまうと、別のURLになってしまいます。 つまり、URLを開く処理の前に、 ・エンコーディングが必要なURLか ・すでにエンコーディングがされているか を判定しないといけないことになります。これは中々煩雑な処理です。 発