Effective Routing with Fluro – A Flutter’s Interesting Prospect

There are many variations of approaches in different areas of Flutter, such as Routing, State Management techniques, Payment Gateways, and so on… In this blog post, we shall be having a detailed conversation regarding Effective Routing with Fluro – A Flutter’s Interesting Prospect. Apart from that, in-between we will look at some code snippets and examples. So let’s deep dive and explore more.


Table of Contents

– Flutter’s Point of View on Routing and Navigations

Flutter provides a profound method for handling Navigation between screens. For this, Flutter provides us with the Navigator Widget. The Navigator Widget acts as a Stack to keep transition animations before the specific platform (Android/iOS/Web).

Additionally, for accessing the Navigator, we need to use the current Route’s BuildContext and call imperative methods (push, pop).

Here’s the complete syntax

Navigator.of(context).push(MaterialPageRoute(
    builder: (context) {
       return OtpScreen();
     },
   ),
 );

In the above snippet:

  • Navigator: Keeps a Stack of Route objects
  • push(): Also takes a route object
  • MaterialPageRoute: A subclass of a route that specifies transition animations

Furthermore, there is an in-depth blog post regarding Routing in Flutter (first heading). Check this out!

Let’s move to the next section and explore the basics of Fluro Routing.

– What makes Fluro Routing stand out?

Fluro claims to be providing the hippest, coolest routing technique for Flutter. Besides this, it has a variety of creative features such as:

  • Route handlers – Map to a function instead of traditional routing
  • Wildcard Parameters – A type argument that controls the type safety when using Generic types <T>
  • Querystring Parameters
  • Built-in transitions
  • Null-Safety support

Let’s now look at the project scenario for this post.

– Project Scenario

Our project is going to be a simple one:

We will be having three-four screens with some random widgets, and in between we shall apply Fluro’s features one by one.

Now let’s look at the current implementation.

– The Implementation

Firstly, add the fluro package to pubspec.yaml with the use of this command:

flutter pub add fluro

Or install it manually, whichever suits you best.

Next, under the lib folder, create a new directory and provide a name respective to our topics – such as routing or navigations.

In this directory, add a new app_routing.dart file.

Next, create a class AppRouting, and define the FluroRouter() instance.

class AppRouting {
 static final FluroRouter router = FluroRouter();
}

Note: It is advisable to make the above instance global for our convenience. You can also do this class as a singleton.

Apart from this, the next thing we need to add is:

A specific handler for each route, in the following format

 var initialScreen = Handler(
  handlerFunc: (BuildContext context, Map<String, dynamic> params) =>
  InitialScreen(),
);

Note: If your project makes use of null-safety, be sure to add ?, after BuildContext in the above snippet.

As per our project scenario, let’s add three more routes, and our complete code snippet should be like this:

 var initialScreen = Handler(
  handlerFunc: (BuildContext context, Map<String, dynamic> params) =>  
  InitialScreen(),
);

 var dashboardScreen = Handler(
  handlerFunc: (BuildContext context, Map<String, dynamic> params) => 
  DashboardScreen(),
);

 var detailScreen = Handler(
  handlerFunc: (BuildContext context, Map<String, dynamic> params) => 
  DetailScreen(),
);

 var profileScreen = Handler(
  handlerFunc: (BuildContext context, Map<String, dynamic> params) => 
  ProfileScreen(),
);

At this point, we need to combine all of these routes into a function that we will use once we initialize our App.

For this, define a function as initRoutes() and provide the following code:

dynamic initRoutes() {
 router.define('/', handler: initialScreen);
 router.define('/dashboard', handler: dashboardScreen);

 /* Do this for the rest as well */
}

We’re good at going.

Here’s the complete code snippet

class AppRouting {
 static final FluroRouter router = FluroRouter();

  var initialScreen = Handler(
  handlerFunc: (BuildContext context, Map<String, dynamic> params) => 
  InitialScreen(),
 );

 var dashboardScreen = Handler(
  handlerFunc: (BuildContext context, Map<String, dynamic> params) => 
  DashboardScreen(),
 );

 var detailScreen = Handler(
  handlerFunc: (BuildContext context, Map<String, dynamic> params) => 
  DetailScreen(),
 );

 var profileScreen = Handler(
  handlerFunc: (BuildContext context, Map<String, dynamic> params) => 
  ProfileScreen(),
 );

 dynamic initRoutes() {
   router.define('/', handler: initialScreen, transitionType:  
     TransitionType.fadeIn);
   router.define('/dashboard', handler: dashboardScreen);
   router.define('/detail', handler: detailScreen);
   router.define('/profile', handler: profileScreen);
 }
}

In addition to this, we can apply Fluro’s feature of Transition in the above function via:

dynamic initRoutes() {
 router.define('/', handler: initialScreen, transitionType: 
   TransitionType.fadeIn);
}

However, there are a dozen of them available which one to use. The choice is yours!

We’re done with this class. It’s time to initialize it under a Stateful Widget.

Head over to the project where we have the sample Counter App. Remove all instances of it, but just the section where StatefulWidget is present.

This should be the code.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      initialRoute: '/',
    );
  }
}

Under the initState, call AppRouting().initRoutes() to load all routes associated with the App itself.

Besides this, we need to add a few lines under MaterialApp as well:

The modified code

import 'package:flutter/material.dart';
import 'package:flutter_useful_tasks/fluro/app_routing.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  @override
  void initState() {
    // TODO: implement initState
    AppRouting().initRoutes();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      initialRoute: '/',
      onGenerateRoute: AppRouting.router.generator,
    );
  }
}

The above snippet has an entity initialRoute, having a string /. This is associated with the very first screen, i.e. InitialScreen.

Note: It is highly recommended to define route titles under a separate file to reduce boilerplate code vis-à-vis handy work.

At this stage, we run the App.

How to Navigate?

We use the same extension, pushNamed

Navigator.pushNamed(context, '/dashboard'),

Note: You can find the complete code from the GitHub Repository at the end of this blog post.

Furthermore, out of four routes, we made use of three, including the profile screen listed with the Dashboard Screen itself.

– Passing arguments

Let’s look at another excellent approach to passing arguments to the next screen. Concerning this, we have a detail_screen as well, which we will use via the Item Screen.

To pass arguments, we use:

ModalRoute.of(context)!.settings.arguments;

A method that returns a current route with params

Again, head over to the Route class and under the handler where you will want to pass arguments.

In our case, it is:

var detailScreen = Handler(
  handlerFunc: (BuildContext context, Map<String, dynamic> params) => 
  DetailScreen(),
 );

Upon modifying the above code

  var detailScreen = Handler(
    handlerFunc: (BuildContext? context, Map<String, dynamic> params) {

      var param = ModalRoute.of(context!)!.settings.arguments as Map<String, 
      String>;
      return DetailScreen(data: param);
    }
  );

Similarly, adding parameters in the UI

onTap: () => Navigator.pushNamed(
context,
'/detail',
arguments: {'item': 'Dummy Product - ${i + 1}'},
),

The Detail Screen UI

Effective Routing with Fluro - Detail Screen

Here we are done with this App.

How about a video preview?

Since it’s an emulator view, there is less chance of a smooth transition. However, for the real device, it would turn out quite nicely.

It’s time to wind up this blog post.

Thank you so much for your precious time.


Summing Up

So, let’s have a quick recap of what we did in this post – Effective Routing with Fluro – A Flutter’s Interesting Prospect. We understood the dynamics of Flutter’s built-in routing. Moreover, we got an idea of how Fluro works, vis-à-vis learning its features and why it claimed to be the best routing plugin in the Flutter market. Furthermore, we acquired knowledge through code snippets, notes in between, and a few screenshots as well.

Besides this, I hope I tried my best according to my limited knowledge and conveyed my message to my audience.

Repo Link – Click Here

You can find me on LinkedIn and YouTube.

Follow my GitHub Repositories

Read out my previous blogs – Click Here

Also, take a look at – An excellent guide to HTTP request handling with Flutter Bloc.

Leave a Comment