🐷

チェックボックスで状態管理を学ぶ

2023/04/18に公開

ボタンのグレーアウトのロジックを作ってみた

退会機能で使うボタンを作ろうとして、ダイアログを出す以外に、CheckBoxを使用して、グレーアウトのロジックを作って、ボタンをうっかり押して、退会してしまうのを防止する方法を考えてみた。
Riverpod2.0のStateNotifierとNotifierを使用して、コードの比較をしてみました。

StateNotifierを使用した状態管理

こちらは、Riverpod2.0では、非推奨になったStateNotifierで作ったロジックです。コンストラクターに初期値を入れて使います。

checkbox_state.dart
import 'package:riverpod/riverpod.dart';

class CheckboxNotifier extends StateNotifier<bool> {
  // コンストラクターに初期値を入れる.
  CheckboxNotifier() : super(false);
  // 状態を持ったメソッドを定義する。等しくなければチェックボックスがONになる.
  // 等しければ、チェックボックスがOFFになる。最初は、OFFの状態.
  void toggle() {
    state = !state;
  }
}

こちらが、アプリを実行するコード。チェックボックスを押すと、ボタンのグレーアウトの状態が切り替わります。

main.dart
import 'package:button_gray_out/checkbox_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Checkbox Example')),
        body: Center(child: MyCheckboxWidget()),
      ),
    );
  }
}

// プロバイダーで読み込む
final checkboxProvider = StateNotifierProvider<CheckboxNotifier, bool>((ref) {
  return CheckboxNotifier();
});

class MyCheckboxWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final isChecked = ref.watch(checkboxProvider);

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Checkbox(
          // if文で切り替わっているかチェックする.
            // onChangedのところでメソッドを実行する.
          value: isChecked,
          onChanged: (bool? newValue) {
            if (newValue != null) {
              ref.read(checkboxProvider.notifier).toggle();
            }
          },
        ),
        ElevatedButton(
          // 三項演算子で、ボタンのグレーアウトの切り替えをする
          onPressed: isChecked
              ? () {
                  // Perform action when the button is pressed
                  print('ElevatedButton pressed');
                }
              : null,
          child: Text('Press me'),
          style: ElevatedButton.styleFrom(
            backgroundColor: isChecked ? Colors.redAccent : Colors.grey,
          ),
        ),
      ],
    );
  }
}

Notifierを使用した状態管理

checkbox_controller.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';

class CheckBoxController extends Notifier<bool> {
  // Notifierはbuildのreturnの中に、初期値を書く.
  // OFFにするので初期値は、false.
  
  build() {
    return false;
  }

  // 状態を持ったメソッドを定義する。等しくなければチェックボックスがONになる.
  // 等しければ、チェックボックスがOFFになる。最初は、OFFの状態.
  void toggle() {
    state = !state;
  }
}

main.dartのコードはわずかしか、変更点がないですね。個人の感想ですが、今までの書き方より、新しい書き方の方がシンプルに書ける気がします。

main.dart
import 'package:button_gray_out/checkbox_controller.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Checkbox Controller')),
        body: Center(child: MyCheckboxWidget()),
      ),
    );
  }
}
// プロバイダーで読み込む
final checkBoxProvider = NotifierProvider<CheckBoxController, bool>(CheckBoxController.new);

class MyCheckboxWidget extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final isChecked = ref.watch(checkBoxProvider);

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Checkbox(
          value: isChecked,
          onChanged: (bool? newValue) {
            // if文で切り替わっているかチェックする.
            // onChangedのところでメソッドを実行する.
            if (newValue != null) {
              ref.read(checkBoxProvider.notifier).toggle();
            }
          },
        ),
        ElevatedButton(
          // 三項演算子で、ボタンのグレーアウトの切り替えをする
          onPressed: isChecked
              ? () {
                  // Perform action when the button is pressed
                  print('Notifier toggle!');
                }
              : null,
          child: Text('Tap'),
          style: ElevatedButton.styleFrom(
            backgroundColor: isChecked ? Colors.redAccent : Colors.grey,
          ),
        ),
      ],
    );
  }
}

実行結果


まとめ

こちらに完成品のソースコードを公開しています。参考にしたい方は見てみてください。
全体のソースコード
https://github.com/sakurakotubaki/ButtonGrayOut

Discussion