我在“MyButton”小部件中使用BlocConsumer,该小部件用于列表中的所有项目。当用户按下按钮时,我希望根据用户单击的按钮将用户重定向到另一个页面(在下面的代码中,打印的是按钮文本)。
如果我运行此代码,单击一个按钮将打印所有文本("Press 1“、"Press 2”、"Press 3")。是否因为完全相同的侦听器被附加到MyButton小部件3次,并且每次单击任何按钮时都会调用所有侦听器?这是否意味着同一页面上的区块不应该有多个小部件?
我可以通过移动BlocConsumer而不是MyButton来包装列来修复代码。这是处理这个问题的正确方法吗?如果是这样的话,我必须在更复杂的情况下包装一个更大的小部件。例如,如果appbar和body中的小部件使用相同的块,那么我将不得不用BlocConsumer包装整个页面。
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() async {
runApp(BlocProvider<MyBloc>(
create: (BuildContext context) => MyBloc(),
child: MaterialApp(
home: Column(
children: [
MyButton(text: "Press 1"),
MyButton(text: "Press 2"),
MyButton(text: "Press 3"),
],
),
),
));
}
class MyButton extends StatelessWidget {
const MyButton({Key? key, required this.text}) : super(key: key);
final String text;
@override
Widget build(BuildContext context) {
return BlocConsumer<MyBloc, MyState>(
listenWhen: (previous, current) {
return true;
},
listener: (context, state) {
print(text);
},
builder: (context, state) {
return TextButton(
key: UniqueKey(),
child: Text(text),
onPressed: () {
context.read<MyBloc>().add(MyEvent());
},
);
},
);
}
}
class MyEvent {}
class MyState {}
class MyBloc extends Bloc<MyEvent, MyState> {
MyBloc() : super(MyState());
@override
Stream<MyState> mapEventToState(MyEvent event) async* {
yield MyState();
}
}发布于 2021-05-25 12:34:33
要在bloc中处理不同的单击,您必须定义事件和状态。
// events
class FirstClick extends Event{}
class SecondClick extends Event{}
class ThirdClick extends Event{}
// states
class FirstClickState extends State{}
class SecondClickState extends State{}
class ThirdClickState extends State{}
// bloc function
class MyBloc extends Bloc<MyEvent, MyState> {
MyBloc() : super(MyState());
@override
Stream<MyState> mapEventToState(MyEvent event) async* {
if(event is FirstClick){
yield FirstClickState();
}
if(event is SecondClick){
yield SecondClickState();
}
if(event is ThirdClick){
yield ThirdClickState();
}
}
}
// view definition
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() async {
runApp(BlocProvider<MyBloc>(
create: (BuildContext context) => MyBloc(),
child: MaterialApp(
home: Column(
children: [
MyButton(text: "Press 1", onPressed:() => BlocProvider.of<MyBloc>(context).add(FirstClick())),
MyButton(text: "Press 2", onPressed:() => BlocProvider.of<MyBloc>(context).add(SecondClick())),
MyButton(text: "Press 3", onPressed:() => BlocProvider.of<MyBloc>(context).add(ThirdClick())),
],
),
),
));
}
class MyButton extends StatelessWidget {
const MyButton({Key? key, required this.text}) : super(key: key);
final String text;
@override
Widget build(BuildContext context) {
return BlocConsumer<MyBloc, MyState>(
listenWhen: (previous, current) {
return true;
},
listener: (context, state) {
if(state is FirstClickState){
// go to where ever
Navigator.push(context, Somewhere());
}
if(state is SecondClickState){
// go to where ever
Navigator.push(context, Somewhere());
}
if(state is ThirdClickState){
// go to where ever
Navigator.push(context, Somewhere());
}
},
builder: (context, state) {
return TextButton(
key: UniqueKey(),
child: Text(text),
onPressed: () {
context.read<MyBloc>().add(MyEvent());
},
);
},
);
}
}发布于 2021-05-28 21:48:46
在页面数未定义的情况下,我使用状态类型为int的Cubit。这允许您拥有任意多的页面,并且页面的索引可以用作cubit的状态。
class PagesCubit extends Cubit<int> {
PagesCubit() : super(0);
void selectPage(int index) => emit(index);
}在你的代码中,你可以这样使用它。
BlocProvider<PagesCubit>(
lazy: false,
create: (BuildContext context) => PagesCubit(),
child: BlocListener<PagesCubit, int>(
listener: (context, state) {
print(state); // expects int value
//TODO: navigate to page
},
child: MaterialApp(
home: Column(
children: [
MyButton(text: "Press 1"),
MyButton(text: "Press 2"),
MyButton(text: "Press 3"),
],
),
),
),
)
//somewhere anywhere else in your code
context.read<PagesCubit>().selectPage(index);注意:除非您知道要导航到的页面,否则不要处理按钮内部的导航。你最终会复制和粘贴大量的代码。相反,您可以将导航拉上一个级别(例如,围绕您的Column ),并在那里管理导航。之所以可以这样做,是因为bloc允许您将代码移动到它提供块的树中的任何位置。
https://stackoverflow.com/questions/67678870
复制相似问题