Saturday, September 29, 2018

Flutter- Screen push and pop with Navigator.

Flutter SDK provides us lot of widgets to create a beautiful screen. Building a user interface with Flutter is pretty simple. To create a big application, we need to create a multi-screen application. We will be required to move around the application or send data back to the screens. 

navigator, push, pop We need to create a multi-screen application that shows all feature of the application in a specific manner. So, users can constantly be navigating between different screens. For example, from a list to a detail screen of product, from a shopping cart to a checkout screen, from a menu into a form, and many other cases.

Flutter provides us navigation and route to manage multi-screen apps. Navigator creates a stack of route object. A Route tells to navigation where to go from now. The stack of navigator keeps track of where all we went from the beginning and how can we come back to the initial state. Flutter uses both Stack and Route to show a new screen of the application. The route tells which page to load and stack makes sure that it’s loaded on top of existing one. To show and hide a screen, navigator provides us Navigator.push and Navigator.pop methods. By using this, a mobile app can reveal their full-content on another screen.


Before starting your multi-screen application. Let's try to understand navigation and route in detail.

The route is an abstraction for a screen of an app. It keeps tags of new screen entered in the stack. For example, '/home' tag will take you to HomeScreen or '/login' tag will take you to LoginScreen. '/' will be root tag of the app.

This is how you would declare your routes in your Flutter application.
Route declaration
new MaterialApp( home: new LandingScreen(), routes: <String, WidgetBuilder> { '/landingscreen': (BuildContext context) => new LandingScreen(), '/loginscreen': (BuildContext context) => new LoginScreen(), '/dashboardscreen': (BuildContext context) => new DashboardScreen() }, )

How can move to another screen?
Let's assume, you are on landing screen on the app and you want to move on the login screen. So, you can call the following method for add a new screen in the stack.
Open new screen
new RaisedButton( onPressed:(){ Navigator.of(context).pushNamed('/login'); },
With the help of pushNamed methods, we can navigate to any login screen.

How can close an open screen?
we would need to pop Routes from the Navigator’s stack using the pop methods.
Close screen
Navigator.of(context).pop();

To manage some complex situation of an app. We have the following method. Let's check all in detail.

* pushReplacementNamed
We can use it to replacing a new screen with an old screen from the top of a stack. Example: Going to HomeScreen from SplashScreen. It should only display once and the user should not be able to go back to it from HomeScreen again. 


* popAndPushNamed
It'll pop a screen from the top of the stack after that push a new screen in a stack. Example: you are building a Shopping app that displays a list of the products in its ProductsListScreen and user can apply filters in the FiltersScreen. When the user clicks on the Apply Changes button, the FiltersScreen should pop and push back to the ProductsListScreen with the new filter values.


* maybePop
Let's assume, you are on initial Route on app and somebody mistakenly tried to pop this screen. Popping the only screen on the stack would close your app because then it has no route to display. You definitely don’t want your user to have such an unexpected user experience. Here, we can use maybePop(). So it’s like, pop only if you can. 


* canPop
The initial route cannot be popped off the navigator, which implies that this function returns true only if popping the navigator would not remove the initial route. It'll return true if this route can be popped and false if it’s not possible.


* pushNamedAndRemoveUntil
Let's assume. you have five screens in the stack of the screens. You want to push a new screen after the second screen and remove all upper screen. In that case, you can use it.  


Let’s take a Shopping app example: Here, we need to do a payment transaction. So in this case, once a user has completed the payment transaction, all the transaction or cart related screens should be removed from the stack, and the user should be taken to the PaymentConfirmationScreen. Clicking on the back button should take them back to the ProductsListScreen or HomeScreen only.
Push Named And Remove Until
Navigator.of(context).pushNamedAndRemoveUntil('/screen4',
ModalRoute.withName('/screen1'));
So according to the code snippet, we push Screen4 and remove all routes until Screen1 so our stack would look like this.

* popUntil 
It'll simply remove all from upper stack screen from given tag.



In this post, we explain the lot of things that we need to create a multi-screen app. Let's start implementation with a simple app now.

Creating a new Project
1. Create a new project from File ⇒ New Flutter Project with your development IDE.

2. Open main.dart file and edit it. As we have set our theme and change debug banner property of Application.
main.dart
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_route_navigation/dashboard.dart'; import 'package:flutter_route_navigation/landingscreen.dart'; import 'package:flutter_route_navigation/loginscreen.dart'; import 'package:flutter_route_navigation/settingscreen.dart'; void main() { runApp(new MaterialApp( debugShowCheckedModeBanner: false, theme: new ThemeData( primaryColor: const Color(0xFF02BB9F), primaryColorDark: const Color(0xFF167F67), accentColor: const Color(0xFFFFFFFF), ),//First screen. home: new SplashScreen(), routes: <String, WidgetBuilder>{ //app routes '/landingscreen': (BuildContext context) => new LandingScreen(), '/loginscreen': (BuildContext context) => new LoginScreen(), '/dashboardscreen': (BuildContext context) => new DashboardScreen(), }, )); } class SplashScreen extends StatefulWidget { @override _SplashScreenState createState() => new _SplashScreenState(); } class _SplashScreenState extends State<SplashScreen> { startTime() async { var _duration = new Duration(seconds: 5); return new Timer(_duration, navigationPage); } void navigationPage() { //landing screen replace with splash screen. Navigator.of(context).pushReplacementNamed('/landingscreen'); } @override void initState() { super.initState(); startTime(); } @override Widget build(BuildContext context) { return new Scaffold( body: new Center( child: new Image.asset('assets/logo.png'), ), ); } }
in the above snippet, we have created a splash screen with a center image and using it for home param of route. It'll our first screen when Flutter launch application. After that, we have declared all route of application. In the splash screen, we have set a 5-second delay for next screen. After 5 seconds the LandingScreen will be visible and landing screen replaces the splash screen tag in the route stack. On the landing screen, if you try to do back press. The app will close. It'll not go to splash screen again.

3. Create a landing screen widget. Here, we just added a button Login. If you click on the login button. It'll increase stack count because the login screen became the top screen of the app.
landingscreen.dart
import 'package:flutter/material.dart'; class LandingScreen extends StatelessWidget { @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text("Landing Screen", style: new TextStyle(color: Colors.white), ), ), body: new Center( child: new Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ new RaisedButton( onPressed: () { Navigator.of(context).pushNamed('/loginscreen'); }, child: new Text("Login"), ), ], ), ), ); } }

4. After that create a login screen widget. It's just a fancy screen that we have designed for real feel on the app. You can log-in in the app just click on the login button.
loginscreen.dart
import 'package:flutter/material.dart'; class LoginScreen extends StatefulWidget { @override _FormState createState() => _FormState(); } class _FormState extends State<LoginScreen> { GlobalKey<FormState> _key = new GlobalKey(); @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( leading: new IconButton( icon: new Icon( Icons.arrow_back, color: Colors.white, ), onPressed: () { Navigator.pop(context); }, ), title: new Text( 'Login', style: new TextStyle(color: Colors.white), ), ), body: new SingleChildScrollView( child: new Container( margin: new EdgeInsets.all(15.0), child: new Form( key: _key, child: getFormUI(), ), ), ), ); } Widget getFormUI() { return new Column( children: <Widget>[ new TextFormField( decoration: new InputDecoration(hintText: 'Email'), maxLength: 32, ), new TextFormField( decoration: new InputDecoration(hintText: 'Password'), keyboardType: TextInputType.phone, maxLength: 10, ), new SizedBox(height: 15.0), new RaisedButton( onPressed: _submit, child: new Text('Login'), ) ], ); } _submit() { //delete all screen from stack and make dashbard as a root of app. Navigator.of(context).pushNamedAndRemoveUntil( '/dashboardscreen', ModalRoute.withName('/')); } }
the motive of the above screen is, make the next screen as a root screen of the app. After login into the app, the dashboard screen will be the first screen. Here, we have a dashboard screen snippet.
dashboardscreen.dart
import 'package:flutter/material.dart'; import 'package:flutter_route_navigation/profilescreen.dart'; class DashboardScreen extends StatelessWidget { @override Widget build(BuildContext context) { return new Scaffold( backgroundColor: Colors.grey, appBar: new AppBar( leading: new Icon(Icons.home,color: Colors.white,), title: new Text("Dashboard", style: new TextStyle(color: Colors.white), ), actions: <Widget>[ new IconButton( icon: new Icon(Icons.account_box,color: Colors.white,), onPressed: () { String userName = "Developer"; Navigator.push( context, new MaterialPageRoute( builder: (BuildContext context) => new ProfilesScreen(userName))); }, ) ], ), body: new Center( child: new Text( "Dashboard Screen", style: new TextStyle(color: Colors.white), ), ), ); } }

now merge the code snippet and run the app. You'll see the final output look like below.

Flutter navigation and route



https://za.gl/91tK                Flutter Push Pop, Send Receive data

I hope, you got the basic idea for a multi-screen app in the Flutter. If you have any doubt and query, please feel free to ask it from the comment section below.



Share:

Get it on Google Play

React Native - Start Development with Typescript

React Native is a popular framework for building mobile apps for both Android and iOS. It allows developers to write JavaScript code that ca...