一般的なチェックボックスのユースケース(設定画面など)においてはLabeledListTile
を使うことで、ラベル付きのチェックボックスが実現できます。しかし、横方向に大量のチェックボックスを並べたいとき(画像参照)には、やはり「ラベル付きのチェックボックス」というウィジェットが欲しいところです。
今回は、私が使っているサンプルを載せますので、適宜カスタムして使ってみてください〜
Table of Contents
- LabeledCheckBox
- 軽い説明
- LabeledRadio
- 軽い説明
LabeledCheckBox
import "package:flutter/material.dart";
class LabeledCheckBox extends StatelessWidget {
final Widget child;
final bool value;
final ValueChanged<bool?>? onChanged;
const LabeledCheckBox({
super.key,
required this.child,
required this.value,
required this.onChanged,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => onChanged?.call(!value),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 32,
height: 32,
child: Checkbox(
value: value,
onChanged: onChanged,
),
),
_animatedChild(context),
],
),
);
}
Widget _animatedChild(BuildContext context) {
final enabledStyle = Theme.of(context).textTheme.labelLarge!.copyWith(
fontSize: 15,
);
final disabledStyle = enabledStyle.copyWith(
color: Theme.of(context).disabledColor,
);
return AnimatedDefaultTextStyle(
style: onChanged != null ? enabledStyle : disabledStyle,
duration: kThemeChangeDuration,
child: child,
);
}
}
軽い説明
Row
でCheckBox
とchild
(ウィジェット)を並べ、最低限必要なパラメータだけを伝搬しています。全体をGestureDetector
でラップしてonChanged
を呼んでいるため、ラベル部分をタップしても反応させることができます。チェックボックスの有効・無効が切り替わったときにテキストの色がアニメーションする機能付き。
LabeledRadio
import "package:flutter/material.dart";
class LabeledRadio<T> extends StatelessWidget {
final T value;
final Widget? label;
final Color? activeColor;
const LabeledRadio({
super.key,
required this.value,
this.label,
this.activeColor,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => RadioGroup.maybeOf<T>(context)?.onChanged(value),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 32,
height: 32,
child: Radio<T>(
value: value,
activeColor: activeColor,
),
),
if (label != null) DefaultTextStyle(
style: Theme.of(context).textTheme.labelLarge!.copyWith(
fontSize: 15,
),
child: label!,
),
],
),
);
}
}
軽い説明
こちらが今回の問題。Flutter 3.35より、Radio
のgroupValue
とonChanged
パラメータが非推奨となり、代わりに親としてRadioGroup
ウィジェットを設置する必要があります。今まではRadio
ごとにonChanged
コールバックを保持していたため、ラベルを押したときにラジオをチェックさせることは簡単でした。しかし、この仕様変更によって、どうにかして値の変更を通知する必要が出てきました。
結論から言うと、RadioGroup.maybeOf
関数を用いてRadioGroupRegistry
を取得し、そのonChanged
メソッドを呼び出すことで、変更を通知できます。しかし、ここに一つ落とし穴が。Radio
が機能するためにはRadioGroup
の型引数T
とすべての子Radio
の型引数T
が同じ型である必要がありますが、RadioGroup.maybeOf
関数にもそれらと同じ型引数を渡す必要があります。 何も渡さないとnullが返却されます。ここでしばらくハマりました。