How to use popUntil properly to reach the root of the stack? - dart

I have pushed to two screen and wish to go back to my main home page. I tried doing that by using popUntil however it is not giving me the req result and just showing a black screen. Do i need to set a new route to my main page , even though i don't want to create a new instance of it ?
My code:
class Completed extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Completed Screen',
home: CompleteScreen(),
routes: <String, WidgetBuilder>{
// "/my-app": (BuildContext context) => MyApp()
}
);
}
}
class CompleteScreen extends StatelessWidget{
#override
Widget build(BuildContext context){
Container Complete = Container(
child: Column(
.....
FlatButton(
onPressed: (){
Navigator.popUntil(
context,
ModalRoute.withName('/'),
);
// Navigator.popUntil(context, ModalRoute.withName(Navigator.defaultRouteName));
},
),
],
));
return Scaffold(
body: Complete
);
}
}
My main page
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: DefaultTabController(length: 2,child: MyHomePage(title: '')),
routes: <String, WidgetBuilder>{
"/TaskScreen": (BuildContext context) => new task(),
}
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
Widget build(BuildContext context){
final list = ListView.builder(
itemBuilder: (context, position) {
return Ink(
child: InkWell(
onTap: (){
Navigator.of(context).pushNamed("/TaskScreen");
},
child: Card(
...
),),); },);
return Scaffold(
...
}
}
I tried using '/TaskScreen' and '/my-app' however even that didn't work.

You could try this
Navigator.popUntil(
context,
ModalRoute.withName(
Navigator.defaultRouteName,
),
),
As defaultRouteName works as the first screen opened when the app starts.
EDIT
So, as mentioned below, named routes won't work with Navigator.defaultRouteNamenor route.isFirst, the best approach to solve this I've found is declaring all your routes in the main page, as these will become global (or that's what I understood), so your code would end something like this
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: DefaultTabController(length: 2,child: MyHomePage(title: '')),
routes: <String, WidgetBuilder>{
"/": (BuildContext context) => MyApp(), (or MyHomePage())
"/TaskScreen": (BuildContext context) => new task(),
}
);
}
}
With that done, anytime you want to go back to the main page you just have to call
Navigator.popUntil(context, ModalRoute.withName('/'));
Hope that works for you.

The route in the popUntil has a property called isFirst that returns true if the route is the first route in the navigator. So in your case, you can use something like:
Navigator.of(context).popUntil((route) {
return route.isFirst;
});

Related

Default back button not showing after pushing new screen

I had pushed a new Screen from my main screen and it had navigated smoothly and also showed the back button however now that I run the button, the default button is not showing in my code.
The only change that I made was that I changed the route in my main file from taskScreen() to task().
But this was essential as i wanted to make some more routes from my second screen and so it had to return a Material App.
How can i get the default back button back?
My code:
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',
home: DefaultTabController(length: 2,child: MyHomePage(title: '')),
routes: <String, WidgetBuilder>{
"/TaskScreen": (BuildContext context) => new task(), //CHANGED HERE
},
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
..
),
body: ...
}
}
My second screen
class task extends StatelessWidget{
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Task',
home: new taskScreen(),
routes: <String, WidgetBuilder>{
"/Completed": (BuildContext context) => new Completed()
}
);
}
}
class taskScreen extends StatefulWidget{
#override
taskState createState() => new taskState();
}
class taskState extends State<taskScreen> {
#override
Widget build(BuildContext context) {
Column taskScreen = Column (...)
return Scaffold(
appBar: AppBar(
title: Text('Task Screen')),
body: taskScreen,
);
}
}
Class name must to start with uppercase character. You have wrong structure, MaterialApp must to be only one time.
https://dart.dev/guides/language/language-tour
For me it happened when I added a draw to all my various AppBars ... quick googling provided a solution which worked for me:
I added to the AppBar the following which let flutter take a conscious decision whether there is or is not what to go back to ...
automaticallyImplyLeading: true,
Then I added defined how the "leading" should look like (also to the appbar):
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context, false),
),
Making a long story short: Adding the following to the respective AppBar did the work:
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context, false),
),
Remove the second routes MaterialApp and replace it with an AppBar

Error: Could not find the correct ScopedModel when using ScopedModel.of<MyModel>(context)

As an outsider looking into flutter state management, I liked the idea of using scoped_model for state management as recommended in flutter.dev. I have a rewrite of the counter app running. I am able to access the model properties using ScopedModelDescendant<CounterModel>, but I am having troubles accessing the model properties using ScopedModel.of<CounterModel>(context). Could someone please advice what I might be doing wrong? I have a hunch that it could be where the ScopedModel is in my widget tree. My code and error message follows.
main.dart
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import 'package:second/model/counter_model.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Widget build(context) {
return ScopedModel(
model: new CounterModel(),
child: Scaffold(
appBar: AppBar(
title: Text('ScopedModel'),
),
body: ScopedModelDescendant<CounterModel>(
builder: (context, child, value) {
return Text("Pressed ${value.counter} times");
},
),
floatingActionButton: buildFab1()),
);
}
Widget buildFab1() {
return ScopedModelDescendant<CounterModel>(
builder: (context, child, model) => FloatingActionButton(
child: Icon(Icons.add),
onPressed: model.incrementCounter,
),
);
}
Widget buildFab2(BuildContext context) {
return FloatingActionButton(
child: Icon(Icons.add),
onPressed: ScopedModel.of<CounterModel>(context).incrementCounter,
);
}
}
model/counter_model.dart
import 'package:scoped_model/scoped_model.dart';
class CounterModel extends Model {
int _counter = 0;
int get counter => _counter;
void incrementCounter() {
_counter++;
notifyListeners();
}
}
In main.dart, if I use buildFab2(context) instead of buildFab1(), I get the following error
flutter: The following ScopedModelError was thrown building ScopedModelDescendant<Model>(dirty):
flutter: Error: Could not find the correct ScopedModel.
flutter:
flutter: To fix, please:
flutter:
flutter: * Provide types to ScopedModel<MyModel>
flutter: * Provide types to ScopedModelDescendant<MyModel>
flutter: * Provide types to ScopedModel.of<MyModel>()
flutter: * Always use package imports. Ex: `import 'package:my_app/my_model.dart';
flutter:
I took a look at a few SO questions, but none helped.
Yes, that because, the context you pass will not have a ScopedModel of CounterModel.
What you can do is wrap your buildFab2 inside a Builder widget which will provide you with a context having ScopedModel with CounterModel as parent.
Like:
Builder(
builder: (context){
return buildFab2(context);
},
)
You app will look like:
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Widget build(context) {
return ScopedModel(
model: new CounterModel(),
child: Scaffold(
appBar: AppBar(
title: Text('ScopedModel'),
),
body: ScopedModelDescendant<CounterModel>(
builder: (context, child, value) {
return Text("Pressed ${value.counter} times");
},
),
floatingActionButton: Builder(
builder: (context) {
// return buildFab1() if fab one required
return buildFab2(context);
},
),
),
);
}
Widget buildFab1() {
return ScopedModelDescendant<CounterModel>(
builder: (context, child, model) => FloatingActionButton(
child: Icon(Icons.add),
onPressed: model.incrementCounter,
),
);
}
Widget buildFab2(BuildContext context) {
return FloatingActionButton(
child: Icon(Icons.add),
onPressed: ScopedModel.of<CounterModel>(context).incrementCounter,
);
}
}
Hope that helps!
You need to add the scoppedmodel in the main.dart like this:
#override
Widget build(BuildContext context){
return ScopedModel<UserModel>(
model: UserModel(),
child: MaterialApp(
title: "Quiz Flamengo",
debugShowCheckedModeBanner: false,
home: Scaffold(
body: HomeScreen(),
)
)
);
}

Navigate to a new screen in Flutter

How do you navigate to a new screen in Flutter?
These questions are similar, but are asking more than I am.
Flutter - Navigate to a new screen, and clear all the previous screens
Flutter: How do I navigate to a new screen using DropDownMenuItems
Flutter: Move to a new screen without back
flutter navigation to new screen not working
I am adding an answer below.
Navigate to a new screen:
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewScreen()));
where context is the BuildContext of a widget and NewScreen is the name of the second widget layout.
Code
main.dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home Screen')),
body: Center(
child: ElevatedButton(
child: const Text(
'Navigate to a new screen >>',
style: TextStyle(fontSize: 24.0),
),
onPressed: () {
_navigateToNextScreen(context);
},
),
),
);
}
void _navigateToNextScreen(BuildContext context) {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewScreen()));
}
}
class NewScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('New Screen')),
body: const Center(
child: Text(
'This is a new screen',
style: TextStyle(fontSize: 24.0),
),
),
);
}
}
See also
Documentation
Navigator and Routes and Transitions... Oh, My! - Simon Lightfoot | Flutter Europe
To load new screens with Flutter pre-canned animations, use their respective transition classes. For example:
Container Transformation
Basically we have the first widget or screen transform into the next screen. For this we need to use OpenContainer. The following code illustrates an item in a ListView transformed to its details page.
#override
Widget build(BuildContext context) {
return Card(
color: Colors.white,
elevation: 2.0,
child: OpenContainer(
transitionType: ContainerTransitionType.fadeThrough,
closedColor: Theme.of(context).cardColor,
closedElevation: 0.0,
openElevation: 4.0,
transitionDuration: Duration(milliseconds: 1500),
openBuilder: (BuildContext context, VoidCallback _) => THENEXTSCREEN(),
closedBuilder: (BuildContext _, VoidCallback openContainer) {
return ListTile(
leading: Icon(Icons.album),
title: Text("ITEM NAME"),
);
},
),
);
}
Shared Axis
This transition is similar to that in Tab or Stepper. We need SharedAxisTransition, PageTransitionSwitcher, along with a state to model transition between active and previous page. If we only switch between two pages we can use a simple boolean isFirstPage for it. Here's the snippet with Provider as state management:
#override
Widget build(BuildContext context) {
return Consumer<YourState>(
builder: (context, state, child) {
return PageTransitionSwitcher(
duration: const Duration(milliseconds: 1500),
reverse: !state.isFirstPage, // STATE
transitionBuilder: (
Widget child,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return SharedAxisTransition(
child: child,
animation: animation,
secondaryAnimation: secondaryAnimation,
transitionType: SharedAxisTransitionType.horizontal,
);
},
child: state.isFirstPage? FIRSTPAGE() : SECONDPAGE(), // STATE
);
},
);
}
Note that in all these scenarios we don't use Navigator and MaterialPageRoute. All these codes are derived from animations repo so you may want to check it out first.
Navigate to next screen with back using Navigator.push()
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),);
Navigate to next screen without back using Navigator.pushReplacement()
Navigator.pushReplacement(
context,MaterialPageRoute(builder: (context) => SecondRoute()),);
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => NextScreenName()));
}
If you are familiar with web development this approach is similar to routing.
main.dart
void main() {
setupLocator();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: {
'/' : (BuildContext context)=>HomePage(),
'/register' : (BuildContext context)=>RegisterPage(),
},
);
}
}
You can add button onPressed event from the homepage.dart to navigate register.dart as follows.
onPressed: (){
Navigator.pushReplacementNamed(context, '/register');
},
Here is a full example of routes push / pop:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Routes',
routes: {
'/login': (BuildContext context) => Login(),
// add another route here
// '/register': (BuildContext context) => Register(),
},
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Routes'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
onPressed: () {
// This gives the back button:
Navigator.of(context).pushNamed('/login');
// This doesn't give the back button (it replaces)
//Navigator.pushReplacementNamed(context, '/login');
},
child: Text('Login'),
),
],
),
),
);
}
}
class Login extends StatefulWidget {
#override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Login Page'),
),
body: Center(
child: RaisedButton(
onPressed: () {
// This will only work for pushNamed
Navigator.of(context).pop();
},
child: Text('Go back'),
),
));
}
}
you can use that way in your build widget
onTap: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => NewScreen()));},
In formal method :
Navigator.push(context, MaterialPageRoute(builder: (context)=>Second()));
In GetX method :
Get.to(Second());
If we can navigate screen into another page and delete current page from stack then we can use method which is define below :
Get.off(Third());
If we can navigate screen into another page and delete all route or page from stack then we can use the method which is define below :
Get.offAll(Third());
If we want to use Navigator.pop() then GetX give a Method which is define below :
Get.back();
You can try with the following code
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => YourNextScreen())),
I found a good tutorial that I have followed along, it is very comprehensive with screenshots and step by step, you can also download the code and just run it. Very helpful for me learning Flutter especially I am totally a begineer.
https://medium.com/#misterflutter/lesson-5-creating-new-screens-f740994190c7
https://medium.com/#misterflutter/lesson-6-creating-new-screens-part-2-4997085a43af?sk=d2a0fb723af42b78800f7cf19b312b62
With the Get plugin, you can navigate to a new page by simply calling
Get.to(Page());
This way you can present the next screen
Navigator.of(context).push(
MaterialPageRoute(fullscreenDialog: true,
builder: (context) => const NewScreen(),
),
);
FloatingActionButton(
onPressed: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context) => const AddUser()));
},
child: const Icon(Icons.add),
),

Change route with Swipe

I want to change a window with a simple swipe to the left, I have to 2 windows and when user swipes to the right side, I want to change my route.
I'm working with Named Routes.
void main() => runApp(new HeatMapApp());
class HeatMapApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'HeatMap',
initialRoute: '/',
routes: {
'/': (context) => new Main(),
'/home': (context) => new Home()
},
theme: new ThemeData(
primaryColor: Colors.black
)
);
}
}
This is my code in my App, the Main file doesn't have too much data now, I want to know the swipe event to redirect to 'home' path.
Main.dart
class Main extends StatelessWidget {
final bool _isLoggedIn = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _isLoggedIn ? AppBar (
title: Text('Logged In')
) : null,
body: Center(
child: Text('Hello World!')
)
);
}
}
I think Dismissible Widget fits perfect on your requirement
class Main extends StatelessWidget {
final bool _isLoggedIn = true;
_nextPage(BuildContext context) async {
Navigator.of(context).pushReplacementNamed("/home");
}
#override
Widget build(BuildContext context) {
return Dismissible(
key: new ValueKey("dismiss_key"),
direction: DismissDirection.endToStart,
child: Scaffold(
appBar: _isLoggedIn ? AppBar(title: Text('Logged In')) : null,
body: Center(child: Text('Hello World!'))),
onDismissed: (direction) {
if (direction == DismissDirection.endToStart) {
_nextPage(context);
}
});
}
}

How do I pass non-string data to a named route in Flutter?

I have many screens, and I'm using the Navigator. I'd like to use "named routes", but I also need to pass non-string (such as images) to my next route.
I can't use pushNamed() because I can't pass non-string data to it.
How can I use a named route + send non-string data?
EDIT:
It is now possible to pass complex arguments to Navigator.pushNamed:
String id;
Navigator.pushNamed(context, '/users', arguments: id);
It can then be used within onGenerateRoute to customize route building with these arguments:
MaterialApp(
title: 'Flutter Hooks Gallery',
onGenerateRoute: (settings) {
final arguments = settings.arguments;
switch (settings.name) {
case '/users':
if (arguments is String) {
// the details page for one specific user
return UserDetails(arguments);
}
else {
// a route showing the list of all users
return UserList();
}
default:
return null;
}
},
);
You can use the parameter routes of your App for directly passing arguments.
Like this:
routes: {
HomePage.route: (_) => HomePage(),
DetailsPage.route: (context) =>
DetailsPage(ModalRoute.of(context).settings.arguments),
},
In this case, the complete example will look like the next:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
initialRoute: HomePage.route,
routes: {
HomePage.route: (_) => HomePage(),
DetailsPage.route: (context) =>
DetailsPage(ModalRoute.of(context).settings.arguments),
},
);
}
}
class HomePage extends StatelessWidget {
static const String route = '/';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, '/details',
arguments: ScreenArguments(
'My Details',
'Some Message',
));
},
),
);
}
}
class DetailsPage extends StatelessWidget {
static const String route = '/details';
final ScreenArguments arguments;
DetailsPage(this.arguments);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(arguments.title),
),
body: Center(
child: Text(arguments.message),
),
);
}
}
class ScreenArguments {
final String title;
final String message;
ScreenArguments(this.title, this.message);
}
By Using Maps
While pushing the arguments u can push that in map form and can do the same while extracting them.
e.g.
While Pushing
Navigator.of(context).pushNamed(
'second',
arguments: {
'title':'This is a String',
or
'Fx': This could be any widget or Function
}
While Extracting the arguments in the target page
final routes=ModalRoute.of(context).settings.arguments as Map<String,String>;
return Scaffold(
appBar: AppBar(
title: Text(routes['title']),
),
body: Container(
child: Center(
child: RaisedButton(
child: Text("Back"),
onPressed: ()=>Navigator.of(context).pop(),
),
),
),
);
and choose your map accordingly accordingly
UPDATE: 3rd April, 2021
This answer is old and Flutter navigation has evolved considerably since then. This may not be the best way to handle navigation with current versions, please consider other answers. I will leave this here for historical purposes.
Using onGenerateRoute it is easy to pass complex arguments on route transition with Navigator.pushNamed or Navigator.pushReplacementNamed
A minimal setup to show the concept would be
main.dart
import 'package:flutter/material.dart';
import 'package:navigator/routes.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Navigation Demo',
theme: ThemeData(
primarySwatch: Colors.teal,
),
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute(
builder: (BuildContext context) => makeRoute(
context: context,
routeName: settings.name,
arguments: settings.arguments,
),
maintainState: true,
fullscreenDialog: false,
);
},
);
}
}
routes.dart
In the _buildRoute method we check the route name and cast arguments to a required type.
A draw back is that the type has to be defined before hand if required argument is not a simple type.
import 'package:flutter/material.dart';
import 'package:navigator/list.dart';
import 'package:navigator/details.dart';
Widget makeRoute(
{#required BuildContext context,
#required String routeName,
Object arguments}) {
final Widget child =
_buildRoute(context: context, routeName: routeName, arguments: arguments);
return child;
}
Widget _buildRoute({
#required BuildContext context,
#required String routeName,
Object arguments,
}) {
switch (routeName) {
case '/':
return ArticleList();
case '/ArticleView':
Article article = arguments as Article;
return ArticleView(article: article);
default:
throw 'Route $routeName is not defined';
}
}
Views
list.dart
Construct the route argument using a defined type, Article in our case.
import 'package:flutter/material.dart';
import 'package:navigator/details.dart' show Article;
class ArticleList extends StatefulWidget {
#override
_ArticleListState createState() => _ArticleListState();
}
class _ArticleListState extends State<ArticleList> {
List<Article> articles = [
Article(
id: 1,
title: 'Article 1',
author_name: 'Nilotpal',
summary: 'Article 1 summary'),
Article(
id: 2,
title: 'Article 2',
author_name: 'Mike',
summary: 'Article 2 summary'),
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Articles'),
),
body: Center(
child: Column(
children: <Widget>[
ListTile(
title: Text('${articles[0].title}'),
subtitle: Text('by ${articles[0].author_name}'),
onTap: () {
Navigator.of(context)
.pushNamed('/ArticleView', arguments: articles[0]);
},
),
ListTile(
title: Text('${articles[1].title}'),
subtitle: Text('by ${articles[1].author_name}'),
onTap: () {
Navigator.of(context)
.pushNamed('/ArticleView', arguments: articles[1]);
},
),
],
),
),
);
}
}
details.dart
Define a type for the arguments
import 'package:flutter/material.dart';
class Article {
final int id;
final String author_name;
final String title;
final String summary;
Article(
{#required this.id,
#required this.author_name,
#required this.title,
#required this.summary});
}
class ArticleView extends StatelessWidget {
final Article _article;
ArticleView({#required Article article}) : _article = article;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('${_article.title}'),
),
body: SafeArea(
top: true,
child: Center(
child: Column(
children: <Widget>[
Text('${_article.author_name}'),
Text('${_article.summary}'),
],
),
),
),
);
}
}
The Flutter Cookbook shows how to navigate to a new page and pass non-string data to it.
Passing data to next page
I started with Navigator.pushedNamed() because it was simple and I didn't have any data to pass. When my needs changed and I wanted to pass data, I switched to Navigator.push().
Example:
var nextPageData = {foo:'bar'};
Navigator.push(
context,
MaterialPageRoute(builder: (context) =>
MyNextPage(myData: nextPageData))
);
I am capturing images with camera then passing them through to a confirmation page like so:
ImagePicker.pickImage(source: source).then((File file) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MediaCaptured(file: file),
));
});
You could easily do the same with any type of file or non-string data.
var foo = "non-string data";
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MediaCaptured(foo: foo),
));
Call the next page in the route by it's class name, as above.
Just make sure your new page accepts this in it's constructor.
// Stateful Widget
class MediaCaptured extends StatefulWidget {
MediaCaptured({ Key key, #required this.foo,}) : super(key: key);
final var foo;
}
// StatelessWidget
class MediaCaptured extends StatelessWidget {
MediaCaptured(this.foo);
var foo;
}
For the outcome of this problem, I developed the package
link: https://pub.dartlang.org/packages/navigate
That provide to much your expect and easy to use
Navigate.navigate(context,
"home",
transactionType:TransactionType.fromLeft , // optional
replaceRoute: ReplaceRoute.thisOne, //optional
arg: {"transactionType":TransactionType.fromLeft,"replaceRoute":ReplaceRoute.thisOne} //optional
);
From First StateFul class :
Navigator.of(context).pushNamed('/pending_order',arguments: {"staff" : staffObj});
To Second StateFul class :
class PendingOrders extends StatefulWidget {
#override
_PendingOrdersState createState() => _PendingOrdersState();
}
class _PendingOrdersState extends State<PendingOrders> {
StaffModel staffModelObj;
#override
Widget build(BuildContext context) {
final routes =
ModalRoute.of(context).settings.arguments as Map<String, dynamic>;
if (routes != null) {
staffModelObj = routes["staff"];
}
return Scaffold(...);}}
I wanted to use a named route navigator that has values as below
Navigator.pushNamed(context, '/increaseBalanceAccountPage',
arguments: {'accountBalanceViewModel': result},);
so I should define that route in materialApp widget in the start of app but I should give parameters in the instance so I solve my problem with some modification of #YuriyLuchaninov code Like below:
MaterialApp(
initialRoute: "/",
routes: {
'/': (context) => SplashScreenPage(),
"/increaseBalanceAccountPage":
(context) =>
UserAccountBalancePage(accountBalanceViewModel: Map<String,Object>
.from(ModalRoute.of(context)!.settings.arguments as Map).values.first as
AccountBalanceViewModel)
},
.....
Consider this trivial example from flutter. You have a class created as follows
class ScreenArguments {
final String title;
final String message;
ScreenArguments(this.title, this.message);
}
Now we will pass an object of this class as an argument as follows
Navigator.pushNamed(
context,
ExtractArgumentsScreen.routeName,
arguments: ScreenArguments(
'Extract Arguments Screen',
'This message is extracted in the build method.',
),
);
And then you can extract the arguments as follows
final args = ModalRoute.of(context)!.settings.arguments as ScreenArguments;
And that is all. Hope this helps Source: passing arguments to a named route
We can pass any type of arguments when declaring routes as constructor arguments as below,
For example to send a list of Strings,
List<String> titles = [];
void main() => runApp(
new MaterialApp(
home: new FirstPage(),
routes: <String, WidgetBuilder>{
"/SecondPage": (BuildContext context) => new SecondPage(titles),
},
),
);
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Container(
child: new RaisedButton(onPressed: () {
Navigator.of(context).pushNamed('/SecondPage');
}),
);
}
}
class SecondPage extends StatelessWidget {
final List<String> titles;
SecondPage(this.titles);
#override
Widget build(BuildContext context) {
return new ListView.builder(
itemBuilder: (context, index) {
return new ListTile(
title: new Text(titles[index]),
);
},
);
}
}

Resources