Flutter BLoC 无法更新我的布尔值列表
Flutter BLoC can't update my list of boolean
所以,我尝试学习 flutter,尤其是在 BLoC 方法中,我用 BLoC 制作了一个简单的 ToggleButtons。这里看起来像
ToggleUI.dart
class Flutter501 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter 50 With Bloc Package',
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
BlocProvider<ToggleBloc>(
builder: (context) => ToggleBloc(maxToggles: 4),
child: MyToggle(),
)
],
),
),
),
);
}
}
class MyToggle extends StatelessWidget {
const MyToggle({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
ToggleBloc bloc = BlocProvider.of<ToggleBloc>(context);
return BlocBuilder<ToggleBloc, List<bool>>(
bloc: bloc,
builder: (context, state) {
return ToggleButtons(
children: [
Icon(Icons.arrow_back),
Icon(Icons.arrow_upward),
Icon(Icons.arrow_forward),
Icon(Icons.arrow_downward),
],
onPressed: (idx) {
bloc.dispatch(ToggleTap(index: idx));
},
isSelected: state,
);
},
);
}
}
ToogleBloc.dart
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
abstract class ToggleEvent extends Equatable {
const ToggleEvent();
}
class ToggleTap extends ToggleEvent {
final int index;
ToggleTap({this.index});
@override
// TODO: implement props
List<Object> get props => [];
}
class ToggleBloc extends Bloc<ToggleEvent, List<bool>> {
final List<bool> toggles = [];
ToggleBloc({
@required int maxToggles,
}) {
for (int i = 0; i < maxToggles; i++) {
this.toggles.add(false);
}
}
@override
// TODO: implement initialState
List<bool> get initialState => this.toggles;
@override
Stream<List<bool>> mapEventToState(ToggleEvent event) async* {
// TODO: implement mapEventToState
if (event is ToggleTap) {
this.toggles[event.index] = !this.toggles[event.index];
}
yield this.toggles;
}
}
当我尝试 Tap/Press 其中一个按钮时出现问题,但它不想更改为活动按钮。但是每当我尝试按下“热重载”时它都会起作用。它喜欢我必须在按下按钮时设置一个 setState。
BlocBuilder.builder
方法仅在 State
改变时执行。因此,在您的情况下,State
是一个 List<bool>
,您只需更改其中的特定索引并生成相同的对象。因此,BlocBuilder 无法确定 List 是否已更改,因此不会触发 UI.
的重建
有关 flutter_bloc
文档中的解释,请参阅 https://github.com/felangel/bloc/blob/master/docs/faqs.md:
Equatable properties should always be copied rather than modified. If an Equatable class contains a List or Map as properties, be sure to use List.from or Map.from respectively to ensure that equality is evaluated based on the values of the properties rather than the reference.
解决方案
在您的 ToggleBloc
中,像这样更改 List,因此它会创建一个全新的 List 对象:
@override
Stream<List<bool>> mapEventToState(ToggleEvent event) async* {
// TODO: implement mapEventToState
if (event is ToggleTap) {
this.toggles[event.index] = !this.toggles[event.index];
this.toggles = List.from(this.toggles);
}
yield this.toggles;
}
此外,请确保为您的活动设置 props
,尽管对于这个特定问题来说这并不重要。
如果新状态等于旧状态,BlocBuilder 将忽略更新。 Dart语言比较两个列表时,如果是同一个实例则相等,否则不相等。
因此,在您的情况下,您必须为每个状态更改创建一个新的列表实例,或者定义一个状态对象并将您的列表作为其中的 属性 发送。
以下是为每个州创建新列表实例的方法:
if (event is ToggleTap) {
this.toggles[event.index] = !this.toggles[event.index];
}
yield List.from(this.toggles);
您可以在此处阅读有关 bloc 库和平等的更多信息:
https://bloclibrary.dev/#/faqs?id=when-to-use-equatable
所以,我尝试学习 flutter,尤其是在 BLoC 方法中,我用 BLoC 制作了一个简单的 ToggleButtons。这里看起来像
ToggleUI.dart
class Flutter501 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter 50 With Bloc Package',
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
BlocProvider<ToggleBloc>(
builder: (context) => ToggleBloc(maxToggles: 4),
child: MyToggle(),
)
],
),
),
),
);
}
}
class MyToggle extends StatelessWidget {
const MyToggle({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
ToggleBloc bloc = BlocProvider.of<ToggleBloc>(context);
return BlocBuilder<ToggleBloc, List<bool>>(
bloc: bloc,
builder: (context, state) {
return ToggleButtons(
children: [
Icon(Icons.arrow_back),
Icon(Icons.arrow_upward),
Icon(Icons.arrow_forward),
Icon(Icons.arrow_downward),
],
onPressed: (idx) {
bloc.dispatch(ToggleTap(index: idx));
},
isSelected: state,
);
},
);
}
}
ToogleBloc.dart
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
abstract class ToggleEvent extends Equatable {
const ToggleEvent();
}
class ToggleTap extends ToggleEvent {
final int index;
ToggleTap({this.index});
@override
// TODO: implement props
List<Object> get props => [];
}
class ToggleBloc extends Bloc<ToggleEvent, List<bool>> {
final List<bool> toggles = [];
ToggleBloc({
@required int maxToggles,
}) {
for (int i = 0; i < maxToggles; i++) {
this.toggles.add(false);
}
}
@override
// TODO: implement initialState
List<bool> get initialState => this.toggles;
@override
Stream<List<bool>> mapEventToState(ToggleEvent event) async* {
// TODO: implement mapEventToState
if (event is ToggleTap) {
this.toggles[event.index] = !this.toggles[event.index];
}
yield this.toggles;
}
}
当我尝试 Tap/Press 其中一个按钮时出现问题,但它不想更改为活动按钮。但是每当我尝试按下“热重载”时它都会起作用。它喜欢我必须在按下按钮时设置一个 setState。
BlocBuilder.builder
方法仅在 State
改变时执行。因此,在您的情况下,State
是一个 List<bool>
,您只需更改其中的特定索引并生成相同的对象。因此,BlocBuilder 无法确定 List 是否已更改,因此不会触发 UI.
有关 flutter_bloc
文档中的解释,请参阅 https://github.com/felangel/bloc/blob/master/docs/faqs.md:
Equatable properties should always be copied rather than modified. If an Equatable class contains a List or Map as properties, be sure to use List.from or Map.from respectively to ensure that equality is evaluated based on the values of the properties rather than the reference.
解决方案
在您的 ToggleBloc
中,像这样更改 List,因此它会创建一个全新的 List 对象:
@override
Stream<List<bool>> mapEventToState(ToggleEvent event) async* {
// TODO: implement mapEventToState
if (event is ToggleTap) {
this.toggles[event.index] = !this.toggles[event.index];
this.toggles = List.from(this.toggles);
}
yield this.toggles;
}
此外,请确保为您的活动设置 props
,尽管对于这个特定问题来说这并不重要。
如果新状态等于旧状态,BlocBuilder 将忽略更新。 Dart语言比较两个列表时,如果是同一个实例则相等,否则不相等。
因此,在您的情况下,您必须为每个状态更改创建一个新的列表实例,或者定义一个状态对象并将您的列表作为其中的 属性 发送。
以下是为每个州创建新列表实例的方法:
if (event is ToggleTap) {
this.toggles[event.index] = !this.toggles[event.index];
}
yield List.from(this.toggles);
您可以在此处阅读有关 bloc 库和平等的更多信息: https://bloclibrary.dev/#/faqs?id=when-to-use-equatable