使用 bloc 触发事件后,底部 sheet 重复显示

bottom sheet is showing repeatedly once event triggred using bloc

我是新手,正在学习如何使用 bloc with freezed。当用户单击浮动操作按钮时,我创建了一个底部 sheet,底部 sheet 出现。底部 sheet 包含文本字段和三个单选组,当我再次单击 select 底部 sheet 弹出的单选按钮时,就像这个 GIF。 https://drive.google.com/file/d/1iU06adGcwjEaw9z2LsmO5xS24CC6OQfT/view?usp=sharing

集团是:

class NoteBloc extends Bloc<NoteEvent, NoteState> {
  NoteBloc() : super(NoteState.initial());

  @override
  Stream<NoteState> mapEventToState(
    NoteEvent event,
  ) async* {
    yield* event.map(
      addNewNoteButtonEvent: (AddNewNoteButtonEvent e) async* {
          yield state.copyWith(
            isAddNewNoteButtonClickedState: e.isClickedEvent,
          );
      },
      radioEvent: (RadioEvent e) async* {
        yield state.copyWith(radioGroupState: e.value);
      },
      textInputEvent: (TextInputEvent e) async* {
        yield state.copyWith(textInputState: Note(value: e.value));
      },
    );
  }
}

事件是:

class NoteEvent with _$NoteEvent {
  const factory NoteEvent.addNewNoteButtonEvent(
      {required bool isClickedEvent}) = AddNewNoteButtonEvent;
  const factory NoteEvent.radioEvent({required int value}) = RadioEvent;
  const factory NoteEvent.textInputEvent({required String value}) =
      TextInputEvent;
}

状态为:

class NoteState with _$NoteState {
  const factory NoteState({
    // required bool showSaveIconState,
    required int radioGroupState,
    required bool isAddNewNoteButtonClickedState,
    required Note textInputState,
  }) = _NoteState;
  // initialize every state
  factory NoteState.initial() => NoteState(
        radioGroupState: 1,
        isAddNewNoteButtonClickedState: false,
        textInputState: Note(value: ''),
      );
}

首页代码为:

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
    return BlocConsumer<NoteBloc, NoteState>(
      listener: (context, state) {
        // if (state is AddNoteClickedState) {
        if (state.isAddNewNoteButtonClickedState) {
          
          // show navigator
          _scaffoldKey.currentState!
              .showBottomSheet((context) => const AddNewNoteBottomSheet())
              .closed
              .then(
            (value) {
              // Change state
              // to tell the bloc that
              // the bottom sheet is closed
              context.read<NoteBloc>().add(
                    const NoteEvent.addNewNoteButtonEvent(
                      isClickedEvent: false, // !state.isAddNewNoteClickedState,
                    ),
                  );
            },
          );
        }
      },
      builder: (context, state) {
        return DefaultTabController(
          length: 3,
          child: Scaffold(
            key: _scaffoldKey,
            // add note float action button
            floatingActionButton: InkWell(
              onTap: () {
                // make button clicked
                // to open the bottom sheet
                context.read<NoteBloc>().add(
                      const NoteEvent.addNewNoteButtonEvent(
                        isClickedEvent: true, //!state.isAddNewNoteClickedState,
                      ),
                    );
                // print(state);
              },
              // for float action button
              // icon shape
              child: Container(
                clipBehavior: Clip.antiAliasWithSaveLayer,
                height: 11.h,
                width: 10.h,
                decoration: BoxDecoration(
                  shape: BoxShape.rectangle,
                  borderRadius: BorderRadius.all(Radius.circular(1.w)),
                  color: const Color(accentColor),
                ),
                // add note icon
                child: Icon(
                  state.isAddNewNoteButtonClickedState ? Icons.save : Icons.add,
                  color: const Color(whiteColor),
                  size: 9.h,
                ),
              ),
        );
      },
    );
  }
}

AddNewNoteBottomSheet 代码为:

// For adding new note
class AddNewNoteBottomSheet extends StatelessWidget {
  const AddNewNoteBottomSheet();

  @override
  Widget build(BuildContext context) {
    TextEditingController _textEditingController = TextEditingController();
    return Container(
      // Contains all
      // bottom sheet components
      child: Column(
              children: [
          // bottom sheet body
          Expanded(
            child: SingleChildScrollView(
              child: BlocBuilder<NoteBloc, NoteState>(
                builder: (context, state) {
                  // print("Helllo ${state.maybeMap(orElse: (){},radioClickState: (stat)=>stat.value)}");
                  return Column(
                    children: [
                      
                      // Today Radio
                      ListTile(
                        title: Text(
                          AppLocalizations.of(context)!.homeTodayTapTitle,
                          style: Theme.of(context)
                              .tabBarTheme
                              .unselectedLabelStyle,
                        ),
                        contentPadding: const EdgeInsets.all(0),
                        autofocus: true,
                        leading: Radio<int>(
                          value: 1,
                          //get group value
                          groupValue: state.radioGroupState,
                          onChanged: (value) {
                            // tell bloc i click you
                            context
                                .read<NoteBloc>()
                                .add(NoteEvent.radioEvent(value: value!));
                          },
                        ),
                      ),
                      // Tomorrow Radio
                      ListTile(
                        contentPadding: const EdgeInsets.all(0),
                        title: Text(
                          AppLocalizations.of(context)!.homeTomorrowTapTitle,
                          style: Theme.of(context)
                              .tabBarTheme
                              .unselectedLabelStyle,
                        ),
                        leading: Radio<int>(
                          value: 2,
                          //get group value
                          groupValue: state.radioGroupState,
                          onChanged: (value) {
                            // tell bloc i click you
                            context.read<NoteBloc>().add(
                                  NoteEvent.radioEvent(value: value!),
                                );
                          },
                        ),
                      ),
                      // Some Day Radio
                      ListTile(
                        contentPadding: const EdgeInsets.all(0),
                        title: Text(
                          AppLocalizations.of(context)!.homeSomeDayTapTitle,
                          style: Theme.of(context)
                              .tabBarTheme
                              .unselectedLabelStyle,
                        ),
                        leading: Radio<int>(
                          value: 3,
                          //get group value
                          groupValue: state.radioGroupState,

                          onChanged: (value) {
                            // tell bloc i click you
                            context.read<NoteBloc>().add(
                                  NoteEvent.radioEvent(value: value!),
                                );
                          },
                        ),
                      ),
                    ],
                  );
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

问题定义: 出现这个问题是因为你在你的bloc上使用了state.copyWith。当您使用 copyWith 时,即使您不更新 isAddNewNoteButtonClickedState 变量,如果您不更改它,您的状态也会保留该值(设置后保持为真,如果您不更改它则永远不会更改)。因为在 copyWith 方法上,更新逻辑的工作方式类似于;

YourState copyWith(bool isAddNewNoteButtonClickedState) {
   return YourState(isAddNewNoteButtonClickedState: isAddNewNoteButtonClickedState ?? this. isAddNewNoteButtonClickedState,)
}

当您产生另一个状态时,此 isAddNewNoteButtonClickedState 保持为真,并且您的侦听器显示另一个模式,因为您的 isAddNewNoteButtonClickedState 没有改变。

解决方法:可以通过(其他状态加上isAddNewNoteButtonClickedState: false)解决这个问题:

    class NoteBloc extends Bloc<NoteEvent, NoteState> {
  NoteBloc() : super(NoteState.initial());

  @override
  Stream<NoteState> mapEventToState(
    NoteEvent event,
  ) async* {
    yield* event.map(
      addNewNoteButtonEvent: (AddNewNoteButtonEvent e) async* {
          yield state.copyWith(
            isAddNewNoteButtonClickedState: e.isClickedEvent,
          );
      },
      radioEvent: (RadioEvent e) async* {
        yield state.copyWith(radioGroupState: e.value, isAddNewNoteButtonClickedState: false);
      },
      textInputEvent: (TextInputEvent e) async* {
        yield state.copyWith(textInputState: Note(value: e.value), isAddNewNoteButtonClickedState: false);
      },
    );
  }
}

补充说明: 由于您不是在 bloc 中转换事件,也不是在做一些琐碎的事情,因此您可以使用 cubit 来简化您的状态管理和业务逻辑。