サイトアイコン IT NEWS

【Flutter】Blocを使ったチェックボックスの状態管理の落とし穴と解決法

Flutterでアプリを開発していると、チェックボックスの状態がうまく切り替わらないという場面に直面することがあります。
特に、Blocによる状態管理を導入している場合、見た目上チェックが入るのに「チェックが外せない」「状態が戻らない」といった現象が発生することがあります。

本記事では、この問題の原因とその解決方法を詳しく解説し、実際にチェックボックスの状態をオン・オフできる実装例を紹介します。
状態の反映が正しく行われずに困っている方、FlutterアプリでBlocを使っている方には、非常に参考になる内容です。

よくある実装ミス:チェックボックスが外せない

次のようなコードでは、チェックボックスをタップして「オン」にはできるものの、もう一度タップして「オフ」に戻すことができません。

Checkbox(
  value: state.isCheck,
  onChanged: (bool? value) {
    context.read<BlocClass>().add(const ToggleCheckedEvent());
  },
)

見た目上は問題ないように見えますが、実際にはチェック状態が常に同じ値に固定されてしまう実装になっています。
多くの場合、イベントを発行するだけで、状態をトグル(切り替える)処理が正しく行われていないことが原因です。

正しい状態管理の考え方

Flutterでの状態管理は「今の状態を変更して、画面に再反映させる」ことが重要です。
上のようなコードで、イベントの内部処理が次のようになっていたとします。

if (state.isCheck == true) {
  emit(state.copyWith(isCheck: true));
} else {
  emit(state.copyWith(isCheck: false));
}

このような処理では、状態を変化させていないため、画面上で再描画が発生せず、チェック状態が固定されたように見えてしまいます。

解決策:状態を反転させる処理を明示する

チェック状態を変更可能にするには、チェックボックスの状態を反転させることが大切です。
以下のように書き直すことで、チェックがオンにもオフにも切り替わるようになります。

Future<void> _onToggleChecked(
  ToggleCheckedEvent event,
  Emitter<AppState> emit,
) async {
  final newChecked = !state.isCheck;
  emit(state.copyWith(isCheck: newChecked));
}

このように状態の反転を明示的に行えば、チェックボックスの状態が正しく切り替わるようになります。

Blocでチェックボックスを制御する実装例

実際の画面表示部分では、以下のように記述します。

Checkbox(
  value: state.isCheck,
  onChanged: (bool? value) {
    context.read<BlocClass>().add(const ToggleCheckedEvent());
  },
)

ここで重要なのは、onChangedの中で新しい値(value)を直接使わず、イベントで処理を委譲し、Bloc側で状態の反転を行うことです。

AbsorbPointerに注意

今回の実装では、チェック済みの場合に再度タップできないようにするため、次のような記述を加えていたかもしれません。

AbsorbPointer(
  absorbing: state.isCheck,
  child: Checkbox(...),
)

この記述があると、チェックされた後に入力がブロックされてしまうため、再びオフに戻すことができなくなります。チェック状態を自由に切り替えたい場合は、この記述を削除するか、別の条件に置き換えるようにしましょう。

実装のポイントまとめ

  • 状態の更新はBloc内で明示的に行うこと
  • 現在の状態と逆の値をemitすることでチェックのトグルが可能
  • AbsorbPointerを使う場合はタップ制御に注意
  • 画面描画の再反映には状態の変化が必要

おわりに

Flutterでチェックボックスの状態管理に悩んでいる方の多くが、今回のように「状態を変えたつもりで変えていない」という落とし穴にはまってしまいます。
正しい状態管理の手順と、Blocパターンの理解を深めることで、より堅牢で使いやすい画面を構築することができます。

この記事が、あアプリ開発の助けとなり、同じような課題に直面した方の一助となれば幸いです。
今後も、現場で役立つ具体的なコード例とともに、問題解決のヒントを発信していきます。

モバイルバージョンを終了