简体   繁体   English

Flutter - 如何使用 Bloc 实现复选框

[英]Flutter - how to implement checkboxes with Bloc

I am trying to create a list with checkboxes with a Select All option at the top.我正在尝试创建一个带有复选框的列表,顶部有一个全选选项。 The current code works fine with the SelectAll/De-selectAll.当前代码适用于 SelectAll/De-selectAll。

The problem is, even the individual checkboxes are working as a SelectAll checkbox.问题是,即使是单个复选框也可以用作 SelectAll 复选框。 Meaning, any checkbox when selected/de-selected, selects/de-selects all other checkboxes.意思是,任何复选框在选中/取消选中时都会选中/取消选中所有其他复选框。

HomePage:主页:

    import 'dart:convert';
    import 'dart:io';
    import 'package:flutter_bloc/flutter_bloc.dart';
    import 'package:http/http.dart' as http;
    import 'package:boost/resources/toast_display.dart';
    import 'package:flutter/material.dart';
    import 'package:internet_connection_checker/internet_connection_checker.dart';
    import '../models/meetings.dart';
    import '../models/test.dart';
    import '../resources/app_strings.dart';
    import '../utils/accesss_token_manager.dart';
    import '../utils/app_urls.dart';
    import '../utils/constants.dart';
    import '../utils/routes.dart';
    import '../widgets/cubit/notification_cubit.dart';

    class NewHomeScreen extends StatefulWidget {
      const NewHomeScreen({Key? key}) : super(key: key);

      @override
      State<NewHomeScreen> createState() => _NewHomeScreenState();
    }

    class _NewHomeScreenState extends State<NewHomeScreen> {
      Meeting meeting = Meeting();
      List<WeeklyMeeting> weeklyMeetingsList = [];
      bool isSelectAll = false;
      bool isMeetingSelected = false;
      final allowNotifications = NotificationSetting(title: 'Allow Notifications');

      final notifications = [
        NotificationSetting(title: 'Show Message'),
        NotificationSetting(title: 'Show Group'),
        NotificationSetting(title: 'Show Calling'),
      ];

      @override
      Widget build(BuildContext context) => Scaffold(
            appBar: AppBar(
              title: const Text('Test'),
            ),
            body: ListView(
              children: [
                buildToggleCheckbox(allowNotifications),
                const Divider(),
                ...notifications.map(buildSingleCheckbox).toList(),
              ],
            ),
          );

      Widget buildToggleCheckbox(NotificationSetting notification) => buildCheckbox(
          notification: notification,
          onClicked: () {
            BlocProvider.of<NotificationSelectionCubit>(context)
                .toggleAllowNotificationSelection();
          });


      Widget buildSingleCheckbox(NotificationSetting notification) => buildCheckbox(
            notification: notification,
            onClicked: () {
              BlocProvider.of<NotificationSelectionCubit>(context)
                  .toggleIndividualNotificationSelection();
            },
          );

      Widget buildCheckbox({
        required NotificationSetting notification,
        required VoidCallback onClicked,
      }) {
        return BlocBuilder<NotificationSelectionCubit, NotificationState>(
          builder: (context, state) {
            return ListTile(
              onTap: onClicked,

 /// stack is used only to give the checkboxes a radio button look, when a checkbox
     is selected it will look like a checked radio button, and when de-selected, it will
     look like an unselected radio button.

              leading: Stack(children: [
                Visibility(
                  visible: state.value,
                  child: Checkbox(
                      shape: const CircleBorder(),
                      value: !state.value,
                      onChanged: (val) {
                        onClicked();
                      }),
                ),
                Visibility(
                  visible: !state.value,
                  child: IconButton(
                    onPressed: () {
                      onClicked();
                    },
                    icon: const Icon(Icons.radio_button_checked),
                  ),
                )
              ]),
              title: Text(
                notification.title,
                style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
            );
          },
        );
      }
    }

NotificationSelectionCubit class NotificationSelectionCubit 类

        class NotificationSelectionCubit extends Cubit<NotificationState> {
      NotificationSelectionCubit()
          : super(NotificationState(value: false, allowNotification: false));
      final allowNotifications = NotificationSetting(title: 'Allow Notifications');

      final notifications = [
        NotificationSetting(title: 'Show Message'),
        NotificationSetting(title: 'Show Group'),
        NotificationSetting(title: 'Show Calling'),
      ];

      void toggleIndividualNotificationSelection() {
        for (var notification in notifications) {
          return emit(NotificationState(
              value: !state.value, allowNotification: state.allowNotification));
        }
      }

      void toggleAllowNotificationSelection() => emit(NotificationState(
          value: state.allowNotification,
          allowNotification: !state.allowNotification));
    }

And

    class NotificationState {
      bool value;
      bool allowNotification;
      NotificationState({required this.value, required this.allowNotification});
    }

You can do it like this:你可以这样做:

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => CheckBoxCubit(),
      child: MaterialApp(
        home: Scaffold(
          body: BlocBuilder<CheckBoxCubit, CheckBoxState>(
            builder: (context, state) {
              return Center(
                child: ListView.builder(
                  itemCount: state.checkBoxes.length,
                  itemBuilder: (context, index) {
                    return CheckboxListTile(
                      title: Text(state.checkBoxes[index]['name']),
                      value: state.checkBoxes[index]['isChecked'],
                      onChanged: (newValue) => context.read<CheckBoxCubit>().toggleNotification(index, newValue),
                    );
                  },
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}

State file is as follows:状态文件如下:

class CheckBoxState {
  List<Map> checkBoxes;

  CheckBoxState({
    required this.checkBoxes,
  });

  CheckBoxState copyWith({
    final List<Map>? checkBoxes,
  }) {
    return CheckBoxState(
      checkBoxes: checkBoxes ?? this.checkBoxes,
    );
  }
}

Cubit file is as follow: Cubit文件如下:

class CheckBoxCubit extends Cubit<CheckBoxState> {
  CheckBoxCubit()
      : super(CheckBoxState(
          checkBoxes: [
            {
              "name": "Foobball",
              "isChecked": false,
            },
            {
              "name": "Baseball",
              "isChecked": false,
            },
          ],
        ));

  void toggleNotification(int index, bool? newValue) => emit(
        state.copyWith(
          checkBoxes: List.from(state.checkBoxes)..[index]['isChecked'] = newValue,
        ),
      );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM