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 stable 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 modal bottom route - A flutter route animation

flutter_modal_bottom_route This is a flutter route animation demo. See Chinouo J

null 4 Aug 19, 2022
Flutter file based routing - File based routing and nested layouts for Flutter

Flutter File Based Routing I was inspired by the routing in remix.run with neste

Rody Davis 10 Sep 29, 2022
A starter kit for beginner learns with Bloc pattern, RxDart, sqflite, Fluro and Dio to architect a flutter project. This starter kit build an App Store app as a example

Flutter Starter Kit - App Store Example A starter kit for beginner learns with Bloc pattern, RxDart, sqflite, Fluro and Dio to architect a flutter pro

kw101 678 Jan 8, 2023
Pasar parametros - App to practice navigation between screens and passing parameters from A->B and B->A

App 5 App para practicar navegacion entre pantallas y paso de parametros de A->B

null 1 Feb 6, 2022
Public interface definitions of Google APIs for Dart and gRPC

Public interface definitions of Google APIs for Dart and gRPC. Getting started I

Mahdi K. Fard 1 Feb 23, 2022
A flutter package that helps you create an on-boarding screen for your project within minutes just by providing a few parameters.

A flutter package that helps you create an on-boarding screen for your project within minutes just by providing a few parameters.

Sachin Kr. Shukla 40 Sep 27, 2022
Clock loader - Highly versatile Widget display the smooth and creative loader named as clock loader

Clock Loader Highly versatile Widget display the smooth and creative loader name

MindInventory 20 Dec 30, 2022
An atomic state management library for dart (and Flutter). Simple, fast and flexible.

nucleus An atomic dependency and state management toolkit. Design goals Simplicity - simple API with no surprises Performance - allow for millions of

Tim 12 Jan 2, 2023
A UI library for easily adding audio waveforms to your apps, with several customization options

A UI library for easily adding audio waveforms to your apps, with several custom

RutvikTak 64 Dec 11, 2022
A fast, flexible, IoC library for Dart and Flutter

Qinject A fast, flexible, IoC library for Dart and Flutter Qinject helps you easily develop applications using DI (Dependency Injection) and Service L

null 4 Sep 9, 2022
A Dart dependency injection library aimed to be flexible, predictable and easy to use.

dino Dino is a Dart dependency injection library with optional code generation. It was inspired by DI in .NET and aimed to be flexible, predictable an

null 3 Dec 20, 2022
A list component that refreshes and adds more data for Flutter.

Language: English | 中文简体 Dynamic List View A list component that can refreshes and adds more data for Flutter App. ?? github Installation Add this to

Sword 18 Sep 27, 2022
Wrapper for flutter_test that adds a tester argument to setUp and tearDown functions

flutter_test_ui Wrapper of testWidgets, setUp, and tearDown that provide the WidgetTesterCallback argument to the set-up and tear-down functions: test

Sander Kersten 12 Apr 10, 2022
Adds a side menu in all screens with debug information

Adds a side menu in all screens with debug information. You can decide which information to show and create new modules to include more information.

Sergi Martínez 27 Oct 7, 2022
This package adds CustomRefreshIndicator widget that allows you to create whatever indicator you want.

Custom Refresh Indicator A flutter package that allows you to easily create a custom refresh indicator widget. TLDR; ONLINE DEMO! QUICK START CustomRe

Kamil Klyta 315 Dec 16, 2022
Flutter The lightest, easiest and most convenient route management!

Language: English | 中文简体 nav_router nav_router is the simplest / lightweight / convenient routing management solution for flutter. It supports various

FlutterCandies 104 Jan 3, 2023
Tic Tac Toe game with single-player and multi-player options. Implemented minimax algorithm.

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

null 0 Jan 1, 2022
This is a message/chat app with light and dark theme options

this is a message/chat app #ui using #flutter that runs both Android and iOS devices also has a dark and light theme. We create in total 4 screens all

Enes Aydoğdu 17 Dec 30, 2022