FLUTTER: How to use navigator in streambuilder?
Solution 1
That's because Flutter is triggering a frame build when you are trying to navigate to another screen, thus, that's not possible.
You can schedule a post frame callback so you can navigate as soon as Flutter is done with tree rebuilding for that widget.
import 'package:flutter/foundation.dart';
WidgetsBinding.instance.addPostFrameCallback(
(_) => Navigator.push(context,
MaterialPageRoute(
builder: (context) => Results(),
),
),
);
Solution 2
If navigation is the only thing happening on a button press, I wouldn't use a Bloc at all because Navigation is not business logic and should be done by the UI layer.
If you have business logic on a button press and need to navigate based on some dynamic information then I would do the navigation again in the presentation layer (widget) in response to a success state like below. You can also change navigation logic as per your requirement.
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;
});
luc
Updated on December 17, 2022Comments
-
luc over 1 year
I am trying to navigate inside a streambuilder but I have this error:"setState() or markNeedsBuild() called during build.". If I call navigate inside an onpressed button it works but not by just use it inside a condition. I am stuck. There is some code to show you.
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'), ); }, ), ); }