Fluro is a Flutter routing library that adds flexible routing options like wildcards, named parameters and clear route definitions.

Overview

English | Português



The brightest, hippest, coolest router for Flutter.

Version Build Status

Features

  • Simple route navigation
  • Function handlers (map to a function instead of a route)
  • Wildcard parameter matching
  • Querystring parameter parsing
  • Common transitions built-in
  • Simple custom transition creation
  • Follows beta Flutter channel
  • Null-safety

Example Project

There is a pretty sweet example project in the example folder. Check it out. Otherwise, keep reading to get up and running.

Getting started

First, you should define a new FluroRouter object by initializing it as such:

final router = FluroRouter();

It may be convenient for you to store the router globally/statically so that you can access the router in other areas in your application.

After instantiating the router, you will need to define your routes and your route handlers:

var usersHandler = Handler(handlerFunc: (BuildContext context, Map<String, dynamic> params) {
  return UsersScreen(params["id"][0]);
});

void defineRoutes(FluroRouter router) {
  router.define("/users/:id", handler: usersHandler);

  // it is also possible to define the route transition to use
  // router.define("users/:id", handler: usersHandler, transitionType: TransitionType.inFromLeft);
}

In the above example, the router will intercept a route such as /users/1234 and route the application to the UsersScreen passing the value 1234 as a parameter to that screen.

Navigating

You can use FluroRouter with the MaterialApp.onGenerateRoute parameter via FluroRouter.generator. To do so, pass the function reference to the onGenerate parameter like: onGenerateRoute: router.generator.

You can then use Navigator.push and the flutter routing mechanism will match the routes for you.

You can also manually push to a route yourself. To do so:

router.navigateTo(context, "/users/1234", transition: TransitionType.fadeIn);

Class arguments

Don't want to use strings for params? No worries.

After pushing a route with a custom RouteSettings you can use the BuildContext.settings extension to extract the settings. Typically this would be done in Handler.handlerFunc so you can pass RouteSettings.arguments to your screen widgets.

/// Push a route with custom RouteSettings if you don't want to use path params
FluroRouter.appRouter.navigateTo(
  context,
  'home',
  routeSettings: RouteSettings(
    arguments: MyArgumentsDataClass('foo!'),
  ),
);

/// Extract the arguments using [BuildContext.settings.arguments] or [BuildContext.arguments] for short
var homeHandler = Handler(
  handlerFunc: (context, params) {
    final args = context.settings.arguments as MyArgumentsDataClass;

    return HomeComponent(args);
  },
);
Comments
  • Error: 'dependOnInheritedWidgetOfExactType' was called on null

    Error: 'dependOnInheritedWidgetOfExactType' was called on null

    I'm getting the following error when calling the Router.generator method:

    The following NoSuchMethodError was thrown building IconTheme(color: Color(0xdd000000)):
    The method 'dependOnInheritedWidgetOfExactType' was called on null.
    Receiver: null
    Tried calling: dependOnInheritedWidgetOfExactType<_InheritedTheme>()
    
    The relevant error-causing widget was
        MaterialApp 
    lib/app.dart:30
    When the exception was thrown, this was the stack
    #0      Object.noSuchMethod  (dart:core-patch/object_patch.dart:53:5)
    #1      Theme.of 
    package:flutter/…/material/theme.dart:128
    #2      Router.matchRoute.<anonymous closure> 
    package:fluro/src/router.dart:130
    #3      Router.matchRoute 
    package:fluro/src/router.dart:183
    #4      Router.generator
    

    It looks like this change may be the source of the bug.

    Is there a reason that null is passed for BuildContext here?

    opened by smkhalsa 25
  • Added ability to define transition type when defining route

    Added ability to define transition type when defining route

    Also updated the test dependency in pubspec.yaml.

    This is just a first pass to get your thoughts...

    It should cover the enhancements needed for https://github.com/theyakka/fluro/issues/27

    enhancement testing 
    opened by jonsamwell 14
  • No registered route was found to handle '/videos/1234'.

    No registered route was found to handle '/videos/1234'.

    I tried to implement routing in my application with fluro, however I had several problems following the 'getting started' guide on Github.

    My implementation is rather simple, since the new GestureDetector( onTap: () { _handleTap(context); }, .... ) is supposed to manually push the route with void _handleTap(BuildContext context) { router.navigateTo(context, "/videos/1234", transition: TransitionType.native); }.

    The router is initialized according to the getting started example, but once I test the app the error

    No registered route was found to handle '/videos/1234'.

    What else is needed in order to push the route, or am I doing something wrong?

    opened by stemuk 11
  • Why pass arguments via routes? Why use Fluro?

    Why pass arguments via routes? Why use Fluro?

    The fluro docs are missing the reason why one would use fluro. It seems to me that the main reason to use fluro is to pass arguments within the route string. But doing so comes with a number of disadvantages relative to passing arguments via objects:

    • You lose compile-time type enforcement for all arguments that aren't ultimately strings. You have to typecast somewhere.
    • You have to reference objects by ID and look them up by ID instead of just getting the object directly. You have to manage unique IDs for objects that wouldn't otherwise have them, and you may need to also cache remotely loaded objects so they're not reloaded on page change.

    I can think of the following possible advantages of passing all arguments via the route:

    • If Flutter eventually supports Android's ability to kill and restart an app in the background, the app could restart on the same page merely by knowing the route. The Flutter team may decide to use the route for this purpose.
    • If you plan to share code between mobile and web versions of your app, by making each mobile page stateless, you're better positioned for doing so.

    Neither of these advantages is realized today. The Flutter team has not decided how to restart Android apps (to my knowledge), and Flutter Web is still too buggy and slow for production.

    So why have you decided to use fluro for argument passing? Is it just for potential future benefit, or are you realizing benefit now? (I'm trying to plan how I should structure my own apps.)

    question stack overflow 
    opened by jtlapp 10
  • Automatic navigation to / route, when opening a keyboard

    Automatic navigation to / route, when opening a keyboard

    When I open a keyboard to type into a TextFormField, I get navigated to the target of the / route.

    main.dart

    class ImmoMatchApp extends StatelessWidget {
      final ImmoNavigator _navigator = new ImmoNavigator();
    
      @override
      Widget build(BuildContext context) {
        _navigator.initRoutes();
        return new MaterialApp(
          title: "ImmoMatch",
          onGenerateRoute: _navigator.router.generator,
        );
      }
    }
    

    ImmoNavigator:

    class ImmoNavigator {
      static final ImmoNavigator _navigator = new ImmoNavigator._internal();
      factory ImmoNavigator() {
        return _navigator;
      }
      ImmoNavigator._internal();
    
      final Logger _logger = new Logger('ImmoNavigator');
      final Router router = new Router();
    
      initRoutes() {
        if (router.match('/') == null) {
          print('initializing routes');
          router.define(
            "/",
            handler: new Handler(
              handlerFunc: (BuildContext context, Map<String, dynamic> params) {
                print("Navigating to Boot");
                return new BootView();
              },
            ),
          );
          router.define(
            "/login",
            handler: new Handler(
              handlerFunc: (BuildContext context, Map<String, dynamic> params) {
                print("Navigating to Login");
                return new LoginView();
              },
            ),
          );
          router.define(
            "/signin",
            handler: new Handler(
              handlerFunc: (BuildContext context, Map<String, dynamic> params) {
                return new SignInView();
              },
            ),
          );
        }
      }
    }
    

    The TextFormField is in the LoginView and when I click on it, "Navigating to Boot" gets printed out.

    investigating information needed 
    opened by tobire 10
  • New direction + maintainer

    New direction + maintainer

    Good news. Fluro is moving to a new home.

    Say hello to @lukepighetti! Luke is one of the most active, enthusiastic and talented Flutter developers there is. I'm glad it's going to a friend.

    I won't get too deep into it but some of the policies adopted by the Flutter team have made it pretty much untenable for Yakka to personally maintain or develop this library. Constant breaking changes and, what we consider to be, generally less than ideal community consultation / collaboration have taken all the "fun" out of providing Fluro to you all.

    I know many of you have already moved on or become frustrated with lack of communication and progress. I've, personally, obsessed over what to do with the project over many months. Many times I thought of shutting it down. However, I think there is still plenty life left in Fluro! There are still lots of cool ideas and everyone is excited for it to move way beyond what we envision.

    Thanks for all your support!

    Luke

    Notice 
    opened by lukef 9
  • ambiguous class name

    ambiguous class name "Router" in Flutter 1.20 (and maybe earlier)

    Describe the bug I upgraded to Flutter 1.20 and there is a name collision:

    error: The name 'Router' is defined in the libraries 'package:fluro/src/router.dart (via package:fluro/fluro.dart)' and 'package:flutter/src/widgets/router.dart (via package:flutter/widgets.dart)'. (ambiguous_import at [flutter_door_buzzer] lib/src/routes.dart:6)
    error: The name 'Router' is defined in the libraries 'package:fluro/src/router.dart (via package:fluro/fluro.dart)' and 'package:flutter/src/widgets/router.dart (via package:flutter/widgets.dart)'. (ambiguous_import at [flutter_door_buzzer] lib/src/routes.dart:6)
    

    To Reproduce

    1. Go to github.com/falkorichter/open-taffeta-mobile-app/tree/macos
    2. run ./flutterw build apk or any other build command

    Expected behavior It should build

    Screenshots image

    Desktop (please complete the following information):

    • OS: [e.g. iOS]
    • Browser [e.g. chrome, safari]
    • Version [e.g. 22]
    opened by falkorichter 9
  • Flutter 1.15 introduces a breaking change

    Flutter 1.15 introduces a breaking change

    Describe the bug A clear and concise description of what the bug is.

    To Reproduce Steps to reproduce the behavior:

    1. Go to '...'
    2. Click on '....'
    3. Scroll down to '....'
    4. See error

    Expected behavior A clear and concise description of what you expected to happen.

    Screenshots If applicable, add screenshots to help explain your problem.

    Desktop (please complete the following information):

    • OS: [e.g. iOS]
    • Browser [e.g. chrome, safari]
    • Version [e.g. 22]

    Smartphone (please complete the following information):

    • Device: [e.g. iPhone6]
    • OS: [e.g. iOS8.1]
    • Browser [e.g. stock browser, safari]
    • Version [e.g. 22]

    Additional context Add any other context about the problem here.

    investigating 
    opened by piratejason 9
  • the reverseTransitionDuration params is not found for PageRouteBuilder

    the reverseTransitionDuration params is not found for PageRouteBuilder

    flutter version

    • Flutter version 1.20.2 at /Library/flutter
    • Framework revision bbfbf1770c (10 weeks ago), 2020-08-13 08:33:09 -0700
    • Engine revision 9d5b21729f
    • Dart version 2.9.1
    

    Xcode's output:

    /Library/flutter/.pub-cache/hosted/pub.flutter-io.cn/fluro-1.7.4/lib/src/fluro_router.dart:223:11: Error: No named parameter with the name 'reverseTransitionDuration'.
              reverseTransitionDuration: transition == TransitionType.none
              ^^^^^^^^^^^^^^^^^^^^^^^^^
    /Library/flutter/packages/flutter/lib/src/widgets/pages.dart:60:3: Context: Found this candidate, but the arguments don't match.
      PageRouteBuilder({
      ^^^^^^^^^^^^^^^^
    

    Command PhaseScriptExecution failed with a nonzero exit code

    If I remove these lines of code

    opened by YufengHu123 8
  • Route Guard and Rerouting

    Route Guard and Rerouting

    Is there a way to implement a simple route guard? For example if the user is not logged in (I can get the info from an inherited widget out of the context) I want to go to the /login page and in the other hand if I am on /login but the user is logged in I want to go to the root of the app. I can't reroute during a Handler or I will get the error, which make sense:

    I/flutter ( 3387): The following assertion was thrown building Builder(dirty):
    I/flutter ( 3387): setState() or markNeedsBuild() called during build.
    I/flutter ( 3387): This Overlay widget cannot be marked as needing to build because the framework is already in the
    I/flutter ( 3387): process of building widgets. A widget can be marked as needing to be built during the build phase
    I/flutter ( 3387): only if one of its ancestors is currently building. This exception is allowed because the framework
    I/flutter ( 3387): builds parent widgets before children, which means a dirty descendant will always be built.
    I/flutter ( 3387): Otherwise, the framework might not visit this widget during this build phase.
    I/flutter ( 3387): The widget on which setState() or markNeedsBuild() was called was:
    I/flutter ( 3387):   Overlay-[LabeledGlobalKey<OverlayState>#46a1c](state: OverlayState#29c46(entries:
    

    I could return the Login page instead of any other page but this looks weird as my Login page will be on the route / or any other route. I can clear the stack after logging in, but still a bit stange no?

    How would you manage redirection?

    question stack overflow 
    opened by Benoss 8
  • Push route without BuildContext

    Push route without BuildContext

    Hey, I've been trying to dig into this for a bit now. What happens if I want to push a route programmatically, say from a listener setup in my main widget constructor.

    class Global {
      static Router router;
    }
    
    void main() {
      runApp(new App());
    }
    
    class App extends StatelessWidget {
      Router router;
    
      App() {
        Global.router = new Router()
          ..define("home",
              handler: new Handler(handlerFunc: (BuildContext context, params) {
            return new HomePage();
          }))
          ..define("auth",
              handler: new Handler(handlerFunc: (BuildContext context, params) {
            return new AuthPage();
          }));
    
        someListener.listen((user) {
          if (user == null) {
            // Do logout, navigate to "auth"
          }
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          onGenerateRoute: Global.router.generator,
        );
      }
    }
    

    I'm trying to find a way to access the root navigator from my listener, and push directly from there.

    This is probably also related to Flutter's built-in navigation.

    What would be a solution?

    question stack overflow 
    opened by Cretezy 8
  • Flutter web: Refreshing dynamic route opens blank page

    Flutter web: Refreshing dynamic route opens blank page

    I encountered an issue while developing a Flutter Web App using the fluro routing system. In the app it is possible to access an overview of plugins as well as a specific plugin detail page. Therefore a fluro router is set up when starting the app:

    void _setupRouter() {
      final router = FluroRouter();
    
      router.notFoundHandler = Handler(handlerFunc: (c, p) => NotFoundPage());
      router.define('/', handler: Handler(handlerFunc: (c, p) => LandingPage()));
      router.define('/plugins', handler: Handler(handlerFunc: (c, p) => const PluginStorageView()));
      var pluginHandler = Handler(handlerFunc: (c, p) => PluginDetailScreen(storageItemId: p['id']?.first ?? 'unknown'));
      router.define('/plugins/:id', handler: pluginHandler);
    
      App.router = router;
    }
    

    When clicking on an plugin in the overview screen, the detail page is opened using this statement:

    App.router.navigateTo(context, '/plugins/${plugin.id}')
    

    All of this works pretty fine opening a webpage looking like this: image

    However, when refreshing the page or opening the app at a specified dynamic route such as mywebsite.com/plugins/1234, the website is just white and not a single element of my Material app is loaded: image

    Is there any way I can access dynamic routes directly using an URL?

    opened by Schloool 0
  • Expected a value of type 'Handler', but got one of type 'Null'

    Expected a value of type 'Handler', but got one of type 'Null'

    I have url : www.foobar.com/template/1234&token=1234 where the first 1234 is the template id. here is my code:

    class CustomRouter {
      static FluroRouter router = FluroRouter();
      static final Handler _splashPage = Handler(
        handlerFunc: ((context, parameters) {
          return const SplashPage();
        }),
      );
      static final Handler _templatePageHandler = Handler(
        handlerFunc: ((context, parameters) {
          String templateId = parameters['tID']!.first;
          return const TemplatePage(templateId: templateId);
        }),
      );
     
      static void defineRoutes() {
        router.define("/", handler: _splashPage);
        router.define(
          "/template/:templateId",
          handler: _templatePageHandler,
          transitionType: TransitionType.fadeIn,
        );
      }
    }
    

    and the app.dart is as:

    class App extends StatefulWidget {
      const App({Key? key}) : super(key: key);
    
      @override
      State<App> createState() => _AppState();
    }
    
    class _AppState extends State<App> {
      @override
      void initState() {
        super.initState();
        CustomRouter.defineRoutes();
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: "Name",
          debugShowCheckedModeBanner: false,
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          onGenerateRoute: CustomRouter.router.generator,
        );
      }
    }
    

    Throws an Expected a value of type 'Handler', but got one of type 'Null'. When I tried running the same code but without the :templateId it works fine.

    opened by fahimhoque 1
  • remove hash from the url

    remove hash from the url

    when I tried to remove the hash from the URL (using setUrlStrategy(PathUrlStrategy()) and https://pub.dev/packages/url_strategy) then the URL path navigation is not working.

    opened by ajeetkumarsah 0
  • notFoundHanler == null

    notFoundHanler == null

    `AppRouteMatch? match = _routeTree.matchRoute(path!); AppRoute? route = match?.route; if (transitionDuration == null && route?.transitionDuration != null) { transitionDuration = route?.transitionDuration; }

    Handler handler = (route != null ? route.handler : notFoundHandler);
    TransitionType? transition = transitionType;
    if (transitionType == null) {
      transition = route != null ? route.transitionType : TransitionType.native;
    }
    if (route == null && notFoundHandler == null) {
      return RouteMatch(
          matchType: RouteMatchType.noMatch,
          errorMessage: "No matching route was found");
    }
    Map<String, List<String>> parameters =
        match?.parameters ?? <String, List<String>>{};
    if (handler.type == HandlerType.function) {
      handler.handlerFunc(buildContext, parameters);
      return RouteMatch(matchType: RouteMatchType.nonVisual);
    }`
    

    if notFoundHandler == null && route == null, Handler handler = (route != null ? route.handler : notFoundHandler); shoud use Handler? handler ,or if (route == null && notFoundHandler == null) can’t execute

    opened by LatCui 0
  • Reloaded web page 404 error

    Reloaded web page 404 error

    I have created web app getting 404 error on reloading web page using browser button so i tried your example code uploaded to my server getting same error 404 when reload the page using browser button

    opened by vishalvishvakarma1111 0
Releases(2.0.3)
Owner
Luke Pighetti
Mobile engineer
Luke Pighetti
Flutter Flows made easy! A Flutter package which simplifies navigation flows with a flexible, declarative API.

Flutter Flows made easy! Usage Define a Flow State The flow state will be the state which drives the flow. Each time this state changes, a new navigat

Felix Angelov 337 Dec 31, 2022
Easy-to-use Navigator 2.0 router for web, mobile and desktop. URL-based routing, simple navigation of tabs and nested routes.

Routemaster Hello! Routemaster is an easy-to-use router for Flutter, which wraps over Navigator 2.0... and has a silly name. Features Simple declarati

Tom Gilder 291 Jan 3, 2023
A simple and easy to learn declarative navigation framework for Flutter, based on Navigator 2.0.

A simple and easy to learn declarative navigation framework for Flutter, based on Navigator 2.0 (Router). If you love Flutter, you would love declarat

Zeno Nine 20 Jun 28, 2022
Fast code and awesome design-ui for flutter navigation bar

Flutter-awesome-bottom-navigation-bar ??‍?? Fast code and awesome design-ui for flutter navigation bar ?? Getting Started # First you need to add flas

Hmida 20 Nov 22, 2022
Flutter Navigation Best Practices including adapting navigation to platform and branding techniques for navigation surfaces.

Flutter Navigation Best Practices including adapting navigation to platform and branding techniques for navigation surfaces.

Fred Grott 5 Aug 22, 2022
A backend server that makes it possible to program with Flutter syntax and reuse existing code

Get Server GetServer allows you to write backend applications with Flutter. Everything here is familiar, from the widgets, to the setState, initState

Jonny Borges 433 Jan 5, 2023
Transparent Android system navigation bar with Flutter and FlexColorScheme package.

Sysnavbar with FlexColorScheme Transparent Android system navigation bar with Flutter and FlexColorScheme. FlexColorScheme V4 Notice If you are using

Rydmike 12 Oct 21, 2022
Simple but powerfull Flutter navigation with riverpod and Navigator 2.0

Riverpod navigation If you are interested in the motivation why the package was created and a detailed description of what problems it solves, read th

pavelpz 20 Dec 13, 2022
Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.

Languages: English (this file), Indonesian, Urdu, Chinese, Brazilian Portuguese, Spanish, Russian, Polish, Korean, French. About Get Installing Counte

Jonny Borges 8k Jan 8, 2023
A Custom Extended Scaffold with Expandable and Floating Navigation Bar

Custom Extended Scaffold Custom Flutter widgets that makes Bottom Navigation Floating and can be expanded with much cleaner a

Ketan Choyal 139 Dec 10, 2022
Elegant abstraction for complete deep linking navigation in Flutter

Flutter Deep Link Navigation Provides an elegant abstraction for complete deep linking navigation in Flutter. This package only provides deep linking

Dennis Krasnov 64 Dec 27, 2022
A Flutter implementation of a customizable navigation bar with animations.

A heavily customizable bottom navigation bar with some animation modifiers.

null 1 Jun 17, 2022
flutter bottom navigation bat project

bottom_navigation A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you starte

Danushan Ravendran 3 Sep 23, 2021
Custom Bottom navigation bar on Flutter.

Intro Custom Bottom navigation bar on Flutter. The updated one Support : Null safety & Support 9 items on Tabs & Some Color, Size, Effects and font cu

Ihab Zaidi 2 Oct 8, 2021
A flutter navigation package

Create By Me(Agalaba Ifeanyi Precious) go Navigate Navigate Like a pro from one Screen to another Using go navigate. go_Navigate provide you the abili

Agalaba Ifeanyi Precious 2 Oct 11, 2021
Flutter Material Design Navigation Drawer Menu

navigation_drawer_menu Flutter Material Design Navigation Drawer Menu Navigation drawer is a common UI pattern for adaptive menus. The Material Design

Christian Findlay 9 Dec 12, 2022
A Flutter package for easily implementing Material Design navigation transitions.

Morpheus A Flutter package for easily implementing Material Design navigation transitions. Examples Parent-child transition You can use MorpheusPageRo

Sander R. D. Larsen 186 Jan 7, 2023
Customized 🚀 Bottom Navigation Bar Using Flutter 🐦

Customized ?? Bottom Navigation Bar Using Flutter ??

AmirHossein Bayat 3 Dec 7, 2022
Flutter custom BottomBar Navigation Widget

bottom_bar_with_sheet ?? Non-standard way to use more space of screens in your application ?? ?? Custom bottom Sheet under Bottom Navigation Bar ?? ??

Stanislav Ilin 305 Dec 23, 2022