一旦使用 bloc 触发事件,底页就会重复显示
Posted
技术标签:
【中文标题】一旦使用 bloc 触发事件,底页就会重复显示【英文标题】:bottom sheet is showing repeatedly once event triggred using bloc 【发布时间】:2021-11-12 09:28:17 【问题描述】:我是一个新手,正在学习如何使用冻结的 bloc。当用户单击浮动操作按钮时,我创建了一个底部工作表,底部工作表出现。当我单击以选择一个收音机时,底部表包含文本字段和三个单选组,底部表再次像此 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!),
);
,
),
),
],
);
,
),
),
),
],
),
);
【问题讨论】:
【参考方案1】:问题定义:出现此问题是因为您在 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);
,
);
补充说明: 由于您不是在整体中转换事件或做一些琐碎的事情,因此您可以使用 cubit 来简化您的状态管理和业务逻辑。
【讨论】:
以上是关于一旦使用 bloc 触发事件,底页就会重复显示的主要内容,如果未能解决你的问题,请参考以下文章
Google Maps API 标记点击事件未触发 [重复]