使用 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 来简化您的状态管理和业务逻辑。
我是新手,正在学习如何使用 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 来简化您的状态管理和业务逻辑。