FLUTTER:如何在 streambuilder 中使用导航器?
FLUTTER: How to use navigator in streambuilder?
我正在尝试在 streambuilder 中导航,但出现此错误:"setState() or markNeedsBuild() called during build."。如果我在按下的按钮内调用导航,它可以工作,但不能仅在条件内使用它。我卡住了。有一些代码可以告诉你。
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream:
Firestore.instance.collection('rooms').document(pinid).snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
if ((snapshot.data['Votes'][0] + snapshot.data['Votes'][1]) >=
snapshot.data['joueurs']) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Results(),
));
}
}
return Center(
child: Text('VOUS AVEZ VOTE'),
);
},
),
);
}
这是因为当您尝试导航到另一个屏幕时,Flutter 会触发框架构建,因此,这是不可能的。
您可以安排一个 post 帧回调,这样您就可以在 Flutter 完成该小部件的树重建后立即导航。
import 'package:flutter/foundation.dart';
WidgetsBinding.instance.addPostFrameCallback(
(_) => Navigator.push(context,
MaterialPageRoute(
builder: (context) => Results(),
),
),
);
如果导航是按下按钮时唯一发生的事情,我根本不会使用 Bloc,因为导航不是业务逻辑,应该由 UI 层完成。
如果您在按下按钮时有业务逻辑并且需要根据一些动态信息进行导航,那么我会在表示层(小部件)中再次进行导航以响应如下所示的成功状态。您还可以根据需要更改导航逻辑。
Widget loginButton(LoginBloc loginBloc) =>
StreamBuilder<List<UserLoginResultElement>>(
stream: loginBloc.loginStream,
builder:
(context, AsyncSnapshot<List<UserLoginResultElement>> snapshot) {
print(snapshot.connectionState);
Widget children;
if (snapshot.hasError) {
children = Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
);
} else {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
case ConnectionState.done:
case ConnectionState.active:
children = BlockButtonWidget(
text: Text(
"LOGIN",
style: TextStyle(color: Theme.of(context).primaryColor),
),
color: Theme.of(context).accentColor,
onPressed: () async {
try {
bloc.submit(_userNameController.value.text,
_passwordController.value.text, context);
} catch (ex) {
print(ex.toString());
}
},
);
break;
}
}
if (snapshot.data != null && snapshot.hasData) {
if (snapshot.data[0].code == "1") {
SchedulerBinding.instance.addPostFrameCallback((_) {
Navigator.pushReplacementNamed(context, "/HomeScreen");
});
} else {
print(Login Failed');
}
}
return children;
});
我正在尝试在 streambuilder 中导航,但出现此错误:"setState() or markNeedsBuild() called during build."。如果我在按下的按钮内调用导航,它可以工作,但不能仅在条件内使用它。我卡住了。有一些代码可以告诉你。
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream:
Firestore.instance.collection('rooms').document(pinid).snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
if ((snapshot.data['Votes'][0] + snapshot.data['Votes'][1]) >=
snapshot.data['joueurs']) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Results(),
));
}
}
return Center(
child: Text('VOUS AVEZ VOTE'),
);
},
),
);
}
这是因为当您尝试导航到另一个屏幕时,Flutter 会触发框架构建,因此,这是不可能的。
您可以安排一个 post 帧回调,这样您就可以在 Flutter 完成该小部件的树重建后立即导航。
import 'package:flutter/foundation.dart';
WidgetsBinding.instance.addPostFrameCallback(
(_) => Navigator.push(context,
MaterialPageRoute(
builder: (context) => Results(),
),
),
);
如果导航是按下按钮时唯一发生的事情,我根本不会使用 Bloc,因为导航不是业务逻辑,应该由 UI 层完成。
如果您在按下按钮时有业务逻辑并且需要根据一些动态信息进行导航,那么我会在表示层(小部件)中再次进行导航以响应如下所示的成功状态。您还可以根据需要更改导航逻辑。
Widget loginButton(LoginBloc loginBloc) =>
StreamBuilder<List<UserLoginResultElement>>(
stream: loginBloc.loginStream,
builder:
(context, AsyncSnapshot<List<UserLoginResultElement>> snapshot) {
print(snapshot.connectionState);
Widget children;
if (snapshot.hasError) {
children = Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
);
} else {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
case ConnectionState.done:
case ConnectionState.active:
children = BlockButtonWidget(
text: Text(
"LOGIN",
style: TextStyle(color: Theme.of(context).primaryColor),
),
color: Theme.of(context).accentColor,
onPressed: () async {
try {
bloc.submit(_userNameController.value.text,
_passwordController.value.text, context);
} catch (ex) {
print(ex.toString());
}
},
);
break;
}
}
if (snapshot.data != null && snapshot.hasData) {
if (snapshot.data[0].code == "1") {
SchedulerBinding.instance.addPostFrameCallback((_) {
Navigator.pushReplacementNamed(context, "/HomeScreen");
});
} else {
print(Login Failed');
}
}
return children;
});