チェックボックスは、ユーザーにon/off設定を切り替えて欲しいときに使います。
FlutterのCheckboxListTile()
は、「チェックボックスの四角い枠」と「表示する文字(ラベル)」がセットで扱える便利なウィジェットです。
Checkbox()
とText()
を個別に組み合わせなくていいし、ラベル部分をクリックしてもチェック操作ができるので、アプリユーザーも使いやすいWidgetです。
この記事では、FlutterのCheckboxListTile()
の基本的な作り方や装飾方法のほか、自分独自の仕様でカスタムウィジェットにしたり、複数のチェックボックスを動的に作成する方法など、少し実践的な事例も紹介します。
- Flutter : 3.27.1
- Dart : 3.6.0
- Android エミュレーター : Pixel 6a Android13.0 (API33)
- iOSシミュレーター : iPhone 15 Pro
チェックボックスの作り方

CheckboxListTile()
で作成したチェックボックス上記のようなチェックボックスをCheckboxListTile()
を使って作っていきます。
StatefulWidgetを用意
チェックボックスは、クリック後のチェックマークの再描画が必要です。
画面を再描画するには、FlutterではsetState
を使うのがまずは一番の基本ですから、setState
を使えるStatefulWidget
を作ります。
ここでは、FlutterのサンプルコードをもとにしたMyHomePage()
を使っていきます。
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(
title: 'Checkbox Try',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
表示する文字列を設定(title:)
title:
は必須項目(required)ではないので、何も表示しない場合は設定しなくてもエラーにはなりません。
でも、ボックスだけならCheckbox()
を使えばいいので、CheckboxListTile()
を使うなら、title:
は用途的には必須項目みたいなもんだと思います。
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(top: 100.0),
child: Column(
children: <Widget>[
CheckboxListTile(
title: Text("Checkbox ListTile"),
値を設定(value:)
チェックボックスがクリックされたときの値を、value:
プロパティ(行番号37)に設定します。value:
はrequired
(必須項目)です。
設定する値は、true
またはfalse
のbool型で、build()
の前で変数を作ります。(行番号26)
ここでは、初期値をfalse
(チェックなし)にして、_isChecked
という名前の変数を作りました。
class _MyHomePageState extends State<MyHomePage> {
bool _isChecked = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(top: 100.0),
child: Column(
children: <Widget>[
CheckboxListTile(
title: Text("Checkbox ListTile"),
value: _isChecked,
クリックされたときの処理を作成(onChanged:)
ボックスがクリックされたときの処理をonChanged:
に書きます。(行番号38)
クリック結果(on/off:true
/false
)を、onChanged:
の引数(value)
(行番号38)で受け取って、setState
に渡します。
setState
では、(value)
の値を_isChecked
に代入します。_isChecked
は、value: _isChecked
で表示する値に設定しているので、新しい値で画面が更新されるというわけです。
ここでは_isChecked
への値の代入しかしてませんが、実際にはこれに続けて何らかの処理を書くことになります。
CheckboxListTile(
title: Text("Checkbox ListTile"),
value: _isChecked,
onChanged: (value) => setState(() {
_isChecked = value!;
}),
行番号39のvalue!
についている!
は、null safety対応の!
で、「絶対にnullにはならない」という意味です。
「null safety」は、値がもしnull
だったときにアプリがフリーズしてしまうことを避けるためにとる対応です。
基本体裁:ボックスの位置(controlAffinity:)

CheckboxListTile()
で表示するボックスは、何も指定しなければ末尾に表示されますが、controlAffinity:
で先頭表示に変更できます。(行番号41)
CheckboxListTile(
title: Text("Checkbox ListTile"),
value: _isChecked,
onChanged: (value) => setState(() {
_isChecked = value!;
}),
controlAffinity: ListTileControlAffinity.leading,
ListTileControlAffinity
*.leading
:先頭
*.trailing
:末尾
*.platform
:表示しているプラットフォーム(AndroidとかiOS)の仕様に依存
基本体裁:アイコン(secondary:)

secondary:
を使うと、ボックスの反対側にアイコン表示ができます。(行番号42)
ボックスが末尾表示なら、アイコンの表示位置は先頭です。
アイコン表示も必須項目ではないので、指定しなければ何も表示されません。
CheckboxListTile(
title: Text("Checkbox ListTile"),
value: _isChecked,
onChanged: (value) => setState(() {
_isChecked = value!;
}),
controlAffinity: ListTileControlAffinity.leading,
secondary: Icon(Icons.supervisor_account_sharp),
少し実践的な実装
カスタムWidgetにする方法

HomeScreen()
からCheckItem()
を呼び出すCheckboxListTile()
を自分仕様にカスタマイズして、別クラスに作成しておくと、どこからでも呼び出せて便利です。
カスタムウィジェットとして別クラスにしておくメリットは、呼び出し元に同じコードをずらずらと並べなくていいことや、仕様変更のときには、カスタムウィジェットのクラスだけ変更すればいいので、メンテナンスが効率的になります。
下のコードでは、[main.dart]のHomeScreen()
の中から、CheckItem()
というクラス名で、2つのCheckboxListTile()
を呼び出しています。(行番号33〜40)
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(top:100.0),
child: Column(
children: <Widget>[
CheckItem(
title: "チェックボックス",
secondary: Icon(Icons.account_circle),
),
CheckItem(
title: "checkbox",
secondary: Icon(Icons.account_circle_outlined),
),
],
),
),
);
}
}
[main.dart]では、カスタムウィジェットとして作成したCheckItem()
を呼び出すときに、title
とsecondary
の値を引数で渡しています。
カスタムウィジェット内に作成するプロパティの名称(ここでは、title:
とsecondary:
)を、実際のWidgetのプロパティ名と同じにしておくと、わかりやすいです。
下記のコードは、カスタムウィジェットとして別クラスに作成した[check_item.dart]ファイルです。
カスタムウィジェットのCheckItem()
では、引数で受け取ったtitle
とsecondary
をCheckboxListTile()
(行番号22)のプロパティに設定して、setState
で再描画しています。
import 'package:flutter/material.dart';
class CheckItem extends StatefulWidget {
const CheckItem({
super.key,
required this.title,// コンストラクタに title を作成
required this.secondary,// 同様に secondary も作成
});
final String title; //コンストラクタに入れる変数を宣言
final Icon secondary; //
@override
State<CheckItem> createState() => _CheckItemState();
}
class _CheckItemState extends State<CheckItem> {
bool isChecked = false;
@override
Widget build(BuildContext context) {
return CheckboxListTile(
title: Text(widget.title),// コンストラクタで受け取ったtitleを指定
value: isChecked,
onChanged: (value) => setState(() {
isChecked = value!;
}),
controlAffinity: ListTileControlAffinity.leading,
secondary: widget.secondary,// コンストラクタで受け取ったtitleを指定
);
}
}
StatefulWidget
で受け取った値をState
の中で使うときは、widget.title
やwidget.secondary
のように、引数名の前にwidget.
をつけて呼び出します。
上記の例では、onChanged:
の処理内容もカスタムウィジェット内で実行するように作成しています。
onChanged:
の内容を、呼び出し元で実行したい場合はこちらを参照

ListView.builder()と組み合わせる方法
CheckboxListTile()
に表示するチェック項目を、あらかじめリスト形式で作成しておくと、ListView.builder()
を使ってリスト項目の数だけ動的に生成することができます。
ListView.builder()
を使うメリットは、動的に作成できるということだけでなく、「画面表示されるときにはじめて、ウィジェットが作られる」ことです。
言い換えると、画面に表示されていないリスト項目はWidgetとして未生成なので、メモリ上にも存在しません。
なので、リスト項目が多い場合、画面表示されるかどうかわからない(スクロール表示されないかもしれない)Widgetをメモリ上に持たないので、メモリの圧迫を最小限に抑えられるという利点があります。
特に、TODOリストでたくさんのリスト項目を表示する場合などは、ListView.builder()
を使うと良いです。
次の例では、ItemData()
というクラスを作って、そのクラスをdata
というリストに20件登録しました。
class ItemData{
const ItemData({required this.title});
final String title;
}
List<ItemData> data =[
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
ItemData(title: "checkbox"),
];
上記のdata
を、[main.dart]から呼び出して使います。
呼び出し元の[main.dart]
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(top:50.0),
child: ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return CheckItem(title: "${data[index].title} ($index)");
},
),
),
);
}
}
ListView.builder()
の引数itemCount:
に、data
リストの個数を指定します。(8行目)
itemBuilder:
は、実際にWidgetを生成している行です。(9行目)
(context, index)
のcontext
はBuildContext
、index
はint型で任意の変数名を指定します。(9行目)
このindex
が、リスト内の何番目のデータなのかをカウントします。
itemBuilder:
プロパティが返す値として、CheckItem()
を指定します。CheckItem()
を呼び出すのは、この1文だけです。(10行目)
CheckItem()
の引数title:
に、"${data[index].title} ($index)"
とすることで、index
がカウントアップしながらdata
リストの値にアクセスしています。
変数に$
を付けているのは、変数の値を文字列として連結するためです。
ここでは、($index)
として、リスト内の何番目なのかを表示しています。
カスタムウィジェット[check_item.dart]
import 'package:flutter/material.dart';
class CheckItem extends StatefulWidget {
const CheckItem({super.key, required this.title});
final String title;
@override
State<CheckItem> createState() => _CheckItemState();
}
class _CheckItemState extends State<CheckItem> {
bool isChecked = false;
@override
Widget build(BuildContext context) {
return CheckboxListTile(
title: Text(widget.title),
value: isChecked,
onChanged: (value) => setState(() {
isChecked = value!;
}),
);
}
}

ListView.builder()
で動的に作成画面表示では20件のデータのうち先頭の13件が描画されました。
これ以降はスクロールすると表示されます。
よく使われるプロパティ(色・罫線・角丸)
CheckboxListTile()
にはたくさんのプロパティがあります。
その中から、色や形状を変えるなどよく使うプロパティの使用例を示しました。
Android

CheckboxListTile()
の色と形状を変更iPhone

CheckboxListTile(
title: Text("タイトル"),
value: _isCheckedJp,
onChanged: (value) => setState(() {
_isCheckedJp = value!;
}),
// アイコン
secondary: Icon(Icons.account_circle),
// チェックボックスの位置(leading・trailing・platform)
controlAffinity: ListTileControlAffinity.leading,
// ラベルの下に表示する補助ラベル
subtitle: Text("サブタイトル"),
// チェックボックスタイル全体の装飾
shape: RoundedRectangleBorder(
// 枠囲み罫線をつける
side: BorderSide(),
// 枠を角丸にする
borderRadius: BorderRadius.circular(8.0),
),
// チェックマークのボックスを角丸にする
checkboxShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4.0),
),
// カラー関連
// 全体の背景色
tileColor: Colors.lightGreen,
// ボックスをチェックしたときの「レ」の色
checkColor: Colors.black,
// ボックスをチェックしたときの「ボックス」の色
activeColor: Colors.red,
)
コメント