Flutter navigation - flutter

Can someone explain why not printing efeioi when it is back from pageE?
Page A
Navigator.pushNamed(context, PageB.ROUTE).then((onValue) {
print("efeioi");
});
Page B
Navigator.of(context)
.pushReplacementNamed(PageC.ROUTE, arguments: onValue);
PageC
Navigator.pushNamed(context, PageD.ROUTE,
arguments: onValue);
PageD
Navigator.pop(context); // back to Page C
Page C
Navigator.pushNamed(context, PageE.ROUTE,
arguments: onValue);
Page E
Navigator.of(context).popUntil(ModalRoute.withName(PageA.ROUTE));
I can't use Navigator.pop in Page E because it will back to Page C!
I have uploaded full code here
https://github.com/tony123S/navigation

As per your requirement I have implemented as below
main.dart
initState : this will be called when you navigate from E to A
refreshPage : it will not called as you already popped before returning to A Page
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: A(),
routes: <String, WidgetBuilder>{
'/A': (BuildContext context) => new A(),
'/B': (BuildContext context) => new B(),
'/C': (BuildContext context) => new C(),
'/D': (BuildContext context) => new D(),
'/E': (BuildContext context) => new E(),
},
);
}
}
class A extends StatefulWidget {
#override
_FirstRouteState createState() => _FirstRouteState();
}
class _FirstRouteState extends State<A> {
final String fromPage;
_FirstRouteState({Key key, #required this.fromPage});
#override
void initState() {
// TODO: implement initState
super.initState();
print("Called askdfjaksdfj");
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page A'),
),
body: Center(
child: RaisedButton(
child: Text('Open B'),
onPressed: () {
// Navigate to second route when tapped.
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => B()),
// );
Navigator.push(
context,
MaterialPageRoute(builder: (context) => B()),
).then((res) => refreshPage());
},
),
),
);
}
refreshPage() {
print("refresh page is called");
}
}
class B extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("B Page"),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
Navigator.of(context).pushNamed(
"/C",
);
},
child: Text('Go to C'),
),
),
);
}
}
class C extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("C Page"),
),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
Navigator.pushNamed(
context,
"/D",
);
},
child: Text('Go to D'),
),
RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
Navigator.pushNamed(
context,
"/E",
);
},
child: Text('Go to E'),
),
],
),
),
);
}
}
class D extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("D Page"),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
Navigator.pop(context);
},
child: Text('Go back to C'),
),
),
);
}
}
class E extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("E Page"),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigator.pop(context);
// Navigator.of(context).pushNamed("/A");
// Navigator.of(context).popUntil(ModalRoute.withName('/A'));
Navigator.of(context)
.pushNamedAndRemoveUntil('/A', (Route<dynamic> route) => false,);
},
child: Text('Go to A'),
),
),
);
}
}
Please run code for better understanding and reply if you found any difficulty

Related

Navigator operation requested with a context that does not include a Navigator in flutter web

I was just put official Doc code for see how Navigation work in web(chrome). But when I click button I get an error->
Navigator operation requested with a context that does not include a Navigator.
code->
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
body: Center(
child: ElevatedButton(
child: Text('Open route'),
// Within the `FirstRoute` widget
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
}),
),
),
);
}
}
class SecondRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: ElevatedButton(
// Within the SecondRoute widget
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
Thanks...

flutter int got to zero

I have a screen with a one button and anotherone with a Container to show a number. I declared a variable in the StatlessWidget class. The button adds 1 to the variable , however after leaving the Class with the container und return to it, I noticed the widgets get updated and my variable loses its value. I have tried initializing it in initState() but it still loses it's value.
import 'package:flutter/material.dart';
import 'package:generator/route_generator.dart';
import 'package:generator/main.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/menu',
onGenerateRoute: RouteGenerator.generateRoute,
);
}
}
class Menu extends StatelessWidget {
int data = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Menu'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
RaisedButton(
onPressed: () {
Navigator.of(context).pushNamed('/second', arguments: data);
},
child: Text('go to the second'),
),
],
),
));
}
}
class FirstPage extends StatelessWidget {
int data = 0;
void eins() {
data = data + 25;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Page'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
data.toString(),
),
RaisedButton(
onPressed: () {
Navigator.pop(context);
Navigator.of(context).pushNamed('/second', arguments: data);
},
child: Text('go to the second'),
),
RaisedButton(
child: Text('25'),
onPressed: eins,
)
],
),
));
}
}
class SecondPage extends StatelessWidget {
int data = 0;
SecondPage({Key key, #required this.data}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
data.toString(),
style: TextStyle(fontSize: 20),
),
RaisedButton(
onPressed: () {
Navigator.of(context).pushNamed('/first');
},
child: Text('go to the first'),
),
],
),
));
}
}
another class
import 'package:flutter/material.dart';
import 'package:generator/main.dart';
import './main.dart';
class RouteGenerator {
static Route<dynamic> generateRoute(RouteSettings settings) {
final args = settings.arguments;
switch (settings.name) {
case '/first':
return MaterialPageRoute(
builder: (_) => FirstPage(),
);
case '/third':
return MaterialPageRoute(
builder: (_) => FirstPage(),
);
case '/menu':
return MaterialPageRoute(
builder: (_) => Menu(),
);
case '/second':
// if (args is int) {
return MaterialPageRoute(
builder: (_) => SecondPage(
data: args,
),
);
//}
// return _errorRoute();
//default:
//return _errorRoute();
}
}
static Route<dynamic> _errorRoute() {
return MaterialPageRoute(builder: (_) {
return Scaffold(
appBar: AppBar(
title: Text('Error'),
),
body: Center(
child: Text('ERROR'),
),
);
});
}
}
The first thing that is weird about your program is that you want to preserve state, in your case a counter variable, but to do that, you select a StatelessWidget. At the very least you will need a StatefulWidget. It's in the name already.
That said, it's not that easy, you may want to look up the different approaches to state management in Flutter: https://flutter.dev/docs/development/data-and-backend/state-mgmt/options
To expand on what #nvoigt said, pick a state management solution instead of passing around arguments from page to page. This way you can keep your widgets stateless, which is preferred but not possible to do what you want to do without a state management solution.
Here's a quick way using GetX state management. This can be done using Provider, RiverPod, Bloc/Cubit...pick your poison.
Here's a new controller class with your data and logic.
class DataController extends GetxController {
int data = 0;
void eins() {
data += 25;
update();
}
}
Then a couple small changes to the rest of your good and you're good to go.
void main() {
Get.put(DataController()); // initializing your controller
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/menu',
onGenerateRoute: RouteGenerator.generateRoute,
);
}
}
class Menu extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Menu'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
RaisedButton(
onPressed: () {
Navigator.of(context).pushNamed('/second');
},
child: Text('go to the second'),
),
],
),
));
}
}
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final controller = Get.find<DataController>(); // finding controller
return Scaffold(
appBar: AppBar(
title: Text('First Page'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
GetBuilder<DataController>( // wrap your text in GetBuilder to display variabe
builder: (_) {
return Text(
controller.data.toString(), // accessing variable via controller
);
},
),
RaisedButton(
onPressed: () {
Navigator.pop(context);
Navigator.of(context).pushNamed('/second');
},
child: Text('go to the second'),
),
RaisedButton(
child: Text('25'),
onPressed: () {
controller.eins(); // accessing function via controller
}),
],
),
));
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final controller = Get.find<DataController>(); // finding same instance of controller on new page
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
GetBuilder<DataController>(
builder: (_) {
return Text(
controller.data.toString(),
);
},
),
RaisedButton(
onPressed: () {
Navigator.of(context).pushNamed('/first');
},
child: Text('go to the first'),
),
],
),
));
}
}
// no longer need to pass anything in your router below
class RouteGenerator {
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case '/first':
return MaterialPageRoute(
builder: (_) => FirstPage(),
);
case '/third':
return MaterialPageRoute(
builder: (_) => FirstPage(),
);
case '/menu':
return MaterialPageRoute(
builder: (_) => Menu(),
);
case '/second':
// if (args is int) {
return MaterialPageRoute(
builder: (_) => SecondPage(),
);
//}
// return _errorRoute();
//default:
//return _errorRoute();
}
}

Flutter how to send data from second page with Navigator.pop

I am trying to get data back from the second screen to the first one:
...
onPressed: () {
sendDataBack(context);
},
...
void sendDataBack(BuildContext context) {
int minSendBack = int.parse(minValueController.text);
int maxSendBack = int.parse(maxValueController.text);
Navigator.pop(context,...);
}
When I use Navigator.pop(context, MaterialPageRout(builder: (context) => main(...)))
I get the error the return type 'void' isn't a 'Widget'. How do I pass two variables back?
Take a look at the following example:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'Returning Data',
home: HomeScreen(),
));
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Returning Data Demo'),
),
body: Center(child: SelectionButton()),
);
}
}
class SelectionButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
_navigateAndDisplaySelection(context);
},
child: Text('Pick an option, any option!'),
);
}
// A method that launches the SelectionScreen and awaits the result from
// Navigator.pop.
_navigateAndDisplaySelection(BuildContext context) async {
// Navigator.push returns a Future that completes after calling
// Navigator.pop on the Selection Screen.
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectionScreen()),
);
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result.
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("$result")));
}
}
class SelectionScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Pick an option'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Yep!" as the result.
Navigator.pop(context, 'Yep!');
},
child: Text('Yep!'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Nope!" as the result.
Navigator.pop(context, 'Nope.');
},
child: Text('Nope.'),
),
)
],
),
),
);
}
}
And read flutter docs carefully.
It's taken from Flutter.dev
you can try this:
in secondScreen Class:
...
onPeressed () {
Navigator.pop(context, returnedData);
}
...
in firstScreen Class:
...
onPeressed () {
result = await Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new secondScreen();
}
...

Refresh listView from PopUntil

Just wonder if I use this code to return PageA from PageD, which function will it get called in PageA?
PageD
Navigator.of(context).popUntil(ModalRoute.withName(PageA.ROUTE));
I would like to make the listView on PageA refreshed once it is back from PageD, but I don't know how to achieve it.
I added a then in PageA, but it is not printing anything.
Navigator.pushNamed(context, PageB.ROUTE).then((onValue) {
print("call from Page4");
_refreshListView();
});
Edit
My project flow is Page A > Page B > Page C > Page D > page A.
All you need to do is return data when you pop PageD and await the data when you push.
This code should help:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/',
routes: {
'/' : (context) => PageA(),
'/go': (context) => PageD()
},
);
}
}
class PageA extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page A"),
),
body: Center(
child: ListView(
children: <Widget>[
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_navigateAndDisplaySelection(context);
},
child: Icon(Icons.forward),
),
);
}
_navigateAndDisplaySelection(BuildContext context) async {
final result = await Navigator.pushNamed(
context,
'/go'
);
if(result){
print(result);
//call the refresh ListView here
_refreshListView();
}
}
}
class PageD extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page D"),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white,),
onPressed: (){
Navigator.pop(context, true);
},
)
),
body: Center(
child: Text("Press back!!"),
),
);
}
}
As to what you explained in the comments... you have to pass arguments from Page D to A when navigating.
Hope this helps.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/',
routes: {
'/': (context) => PageA(),
'/b': (context) => PageB(),
'/c': (context) => PageC(),
'/d': (context) => PageD()
},
);
}
}
class PageA extends StatelessWidget {
#override
Widget build(BuildContext context) {
final bool shouldRefresh = ModalRoute.of(context).settings.arguments;
if (shouldRefresh != null) {
print(shouldRefresh);
//call the refresh ListView here
_refreshListView();
}
return Scaffold(
appBar: AppBar(
title: Text("Page A"),
),
body: Center(
child: ListView(
children: <Widget>[],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, '/b');
},
child: Icon(Icons.forward),
),
);
}
}
class PageB extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page B"),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.forward),
onPressed: () {
Navigator.pushNamed(context, '/c');
},
),
);
}
}
class PageC extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page C"),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.forward),
onPressed: () {
Navigator.pushNamed(context, '/d');
},
),
);
}
}
class PageD extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page D"),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.white,
),
onPressed: () {
Navigator.pushNamed(context, '/', arguments: true);
},
)),
body: Center(
child: Text("Press back!!"),
),
);
}
}
If you want to go to Page D when you press back in Page A then use this
class PageA extends StatelessWidget {
#override
Widget build(BuildContext context) {
final bool shouldRefresh = ModalRoute.of(context).settings.arguments;
print(shouldRefresh);
return Scaffold(
appBar: AppBar(
title: Text("Page A"),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.white,
),
onPressed: () {
Navigator.pushNamed(
context,
'/d',
arguments: true
);
},
),
),
body: Center(
child: ListView(
children: <Widget>[
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, '/b');
},
child: Icon(Icons.forward),
),
);
}
}

How to remove the second appbar in Flutter

I am trying to build a demo chat app with Flutter. After my main screen, I am using Navigator.push to go to the details screen.
Screenshot of problem:
build method of 1st screen:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Chat Thread App"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
onPressed: () {
Navigator.pushNamed(context, '/settings');
},
)
],
),
body: isLoading
? Center(
child: CircularProgressIndicator(),
)
: new ChatThreadListCard(messageThreads: _messageThreadLists, user: _user,),
);
}
code of Navigator.push method:
Navigator.push(context, MaterialPageRoute(
builder: (context) => ChatDetailsScreen(threadModel: new ThreadModel(
user.id,
user.fullName,
user.pic,
"otherId",
"otherName",
"otherPic",
post.threadId
)
),
),);
build method of 2nd screen, where the problem is produced:
return Scaffold(
appBar: AppBar(
title: Text("Chat demo"),
),
body: WillPopScope(
child: isLoading
? Center(
child: CircularProgressIndicator(),
)
: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: <Widget>[
SizedBox(
width: 300,
height: 300,
),
Column(
children: <Widget>[
buildChat(),
buildInput(),
],
)
],
),
onWillPop: onBackPress,
),
);
the problem turns out to be, i was creating a MaterialApp widget in scaffold's body. so, when the onTap method was called, the new screen was replaced insdie the MaterialApp's area. didnt replace the whole screen.
the trick was to remove the return new MaterialApp().
thanks everyone.
I'm guessing something isn't working right with where you're setting up the Material App?
app.dart:
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage());
}
}
home_page and second_page
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
State createState() => HomePageState();
}
class HomePageState extends State<HomePage> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Page'),
),
body: Container(
child: Center(child: RaisedButton(child: Text('Forward'), onPressed: () async {
await Navigator.push(context, MaterialPageRoute(builder: (context) => SecondPage()));
},)),
));
}
}
class SecondPage extends StatefulWidget {
#override
State createState() => SecondPageState();
}
class SecondPageState extends State<SecondPage> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Container(
child: Center(child: RaisedButton(child: Text('Backward'), onPressed: () {
Navigator.of(context).pop();
},)),
));
}
}
Which produces: