Declaratively switch child widgets based on the current `Router` location.

Overview

Build Status Build Status

Features

Declaratively switch child widgets based on the current Router location.

class SideBar extends StatelessWidget {
    Widget build(_){
     return RoutedWidgetSwitcher(
        builders: [
            PathBuilder('/', builder: (_) => const MainMenu()),
            PathBuilder('/dashboard', builder: (_) => const DashboardMenu()),
            PathBuilder('/settings', builder: (_) => const SettingsMenu()),
        ]);
    }
}

Intended as a complimentary package for any Router (aka Nav2) implementation. Including popular routing solutions like GoRouter, RouteMaster or VRouter.

This is useful in 2 primary use cases:

  • when you have scaffolding around your Navigator, like a SideBar or a TitleBar and you would like it to react to location changes
  • when multiple paths resolve to the same Page and you want to move subsequent routing further down the tree

Note: This package does not provide any control of the routers location, it simply reads the current location and responds accordingly.

🔨 Installation

dependencies:
  routed_widget_switcher: ^1.0.0

🕹️ Usage

Place the widget anywhere below the root Router widget and define the paths you would like to match. By default paths are considered to be case-insensitive, and treated as prefixes, but this can be disabled:

return RoutedWidgetSwitcher(
  caseSensitive: true,
  builders: [
    // require an exact match if prefix=false
    PathBuilder('/', prefix: false, builder: (_) => const MainMenu()),
     // allow anything prefixed with `/dashboard`
    PathBuilder('/dashboard', builder: (_) => const DashboardMenu()),
  ],
);

Path matching

Paths can be defined as simple strings like /user/new or user/:userId, or use regular expression syntax like r'/user/:id(\d+). See pathToRegExp library for more details on advanced use cases: https://pub.dev/packages/path_to_regexp.

In addition to the matching performed by pathToRegExp, a wildcard * character can be used to match any location.

Most specific match

RoutedWidgetSwitcher will attempt to use the most specific match. For example,the location of /users/new matches all three of these builders:

PathBuilder('/users/:userId', builder: (_) => const TeamDetails()),
PathBuilder('/users/new', builder: (_) => const NewTeamForm()),
PathBuilder('*', builder: (_) => const PathNotFound()),

Since /users/new is the more exact match, it will be the one to render, it does not matter which order you declare them in. /users/:userId would go next, with the wildcard '*' finally matching last.

Getting current location

This package includes a RouterUtils.getLocation(context) method which will return the current router location if you would like to read it for some reason.

Transitions

Internally Flutters AnimatedSwitcher widget is used for transitions, so that full API is exposed for different transition effects.

return RoutedWidgetSwitcher(
  transitionBuilder: ...
  duration: ...,
  builders: [],
)

🐞 Bugs/Requests

If you encounter any problems please open an issue. If you feel the library is missing a feature, please raise a ticket on Github and we'll look into it. Pull request are welcome.

📃 License

MIT License

You might also like...

A flutter widget which renders its child outside the original widget hierarchy.

 A flutter widget which renders its child outside the original widget hierarchy.

overlay_container A flutter widget which renders its child outside the original widget hierarchy. Demo. This demo is present as an example here. You c

Jun 10, 2022

Helper for building advanced multi child layouts.

Helper for building advanced multi child layouts.

About Boxy is designed to overcome the limitations of Flutter's built-in layout widgets, it provides utilities for flex, custom multi-child layouts, d

Dec 12, 2022

A ListView widget capable of pinning a child to the top of the list.

PinnableListView A Flutter ListView widget that allows pinning a ListView child to the top of the list. Demo Getting Started Define the list PinCont

May 17, 2020

This widget automatically scrolls the custom child widget to an infinite loop.

This widget automatically scrolls the custom child widget to an infinite loop.

Scroll Loop Auto Scroll This widget automatically scrolls the custom child widget to an infinite loop. Example Features Infinite Auto Scroll Custom ch

Dec 12, 2022

Venda is a location-based business platform

Venda is a location-based business platform

Venda (vendaround.com) Venda is a location-based business platform that enables people to discover businesses around them. With Venda, you can sell or

Jul 24, 2022

Map location picker for flutter Based on google_maps_flutter

Map location picker for flutter Based on google_maps_flutter

map_location_picker: A simple library to pick a location on a map. Made by Arvind @rvndsngwn: Compatibility with Geolocator Use of Google map APIs Add

Nov 27, 2022

A beautiful switch made with Flutter

A beautiful switch made with Flutter

Crazy Switch Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this is your first Flut

Nov 20, 2022

An interesting and practical switch component.

An interesting and practical switch component.

FSwitch An interesting and practical switch component. Supports setting tips, slider decorations, shadows, and good interaction. Author:Newton(coorchi

Dec 13, 2022

An easy to implement custom switch created for Flutter.

An easy to implement custom switch created for Flutter.

flutter_switch An easy to implement custom switch created for Flutter. Give it a custom height and width, border for the switch and toggle, border rad

Dec 6, 2022
Comments
  • Refactoring

    Refactoring

    Using scheduleMiscrotask in initState is a very very very bad idea!

    Instead of https://github.com/gskinnerTeam/flutter-routed-widget-switcher/blob/master/lib/routed_widget_switcher.dart#L41-L46 you may:

    @override
    void didChangeDependencies() {
      delegate ??= Router.of(context).routerDelegate..addListener(_handleRouteChanged);
      provider ??= Router.of(context).routeInformationProvider..addListener(_handleRouteChanged);
      super.didChangeDependencies();
    }
    

    But anyway, is a bad idea to do what you do that way

    Just use AnimatedBuilder, like that:

    class YourWidget extends StatelessWidget {
       @override
       Widget build(_) => AnimatedBuilder(
          animation: Listenable.merge(<Listenable>[
            Router.of(context).routerDelegate,
            Router.of(context).routeInformationProvider,
          ]),
          builder: ...
       );
    }
    
    opened by PlugFox 4
  • Not working with VRouter

    Not working with VRouter

    When running the integration test in the example folder, I get this failure :

    00:00 +0: VRouter
    [VRouter: INFO] Successfully navigated to "/" using VRouter.to o
    [VRouter: INFO] Successfully navigated to "/dashboard" using VRouter.to o
    ══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
    The following TestFailure object was thrown running a test:
      Expected: exactly one matching node in the widget tree
      Actual: _WidgetTypeFinder:<zero widgets with type "DashboardMenu" (ignoring offstage widgets)>
       Which: means none were found but one was expected
    

    As you can see, the Sidebar doesn't react to the route changes.

    Here is a simplified example where you can verify that it's indeed not working : (Press on the FAB to go to a random path)

    import 'dart:math';
    
    import 'package:flutter/material.dart';
    import 'package:routed_widget_switcher/routed_widget_switcher.dart';
    import 'package:vrouter/vrouter.dart';
    
    void main() {
      runApp(VRouterApp());
    }
    
    class VRouterApp extends StatelessWidget {
      const VRouterApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return VRouter(
            builder: (_, navigator) {
              // Wrap the navigator in a simple scaffold, with a persistent `SideBar` on the left
              return Row(
                children: [
                  const SideBar(),
                  Expanded(child: navigator),
                ],
              );
            },
            routes: [
              VWidget.builder(
                path: '*',
                builder: (_, data) => MainScaffold(data.url ?? ''),
              ),
            ]);
      }
    }
    
    class SideBar extends StatelessWidget {
      const SideBar({Key? key}) : super(key: key);
      @override
      Widget build(BuildContext context) {
        Widget buildSideBarBg(Widget child) =>
            Material(child: SizedBox(width: 180, child: child));
        return buildSideBarBg(
          RoutedSwitcher(
            builders: (info) {
              // PROBLEM : Always prints '/'
              print(info.url);
              return [
                // Wildcard will match any route
                Routed('*', MainMenu.new),
                Routed('/dashboard', DashboardMenu.new),
                Routed('/settings', SettingsMenu.new),
              ];
            },
          ),
        );
      }
    }
    
    class MainScaffold extends StatelessWidget {
      final String location;
    
      static const paths = [
        '/',
        '/pageA',
        '/pageB',
        '/dashboard',
        '/dashboard/foo',
        '/dashboard/bar',
        '/settings',
        '/settings/foo',
        '/settings/bar',
      ];
    
      static final random = Random();
    
      const MainScaffold(this.location, {Key? key}) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            floatingActionButton: FloatingActionButton(
              onPressed: () {
                final int i = random.nextInt(9);
    
                context.vRouter.to(paths[i]);
              },
            ),
            body: SafeArea(
              child: Center(child: Text(location)),
            ));
      }
    }
    
    /// Stub
    class MainMenu extends StatelessWidget {
      MainMenu({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) => Container(
            color: Colors.red,
            child: const Center(
              child: Text('MAIN MENU'),
            ),
          );
    }
    
    /// Stub
    class DashboardMenu extends StatelessWidget {
      DashboardMenu({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) => Container(
            color: Colors.blue,
            child: const Center(
              child: Text('DASHBOARD\nMENU'),
            ),
          );
    }
    
    /// Stub
    class SettingsMenu extends StatelessWidget {
      SettingsMenu({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) => Container(
            color: Colors.green,
            child: const Center(
              child: Text('SETTINGS MENU'),
            ),
          );
    }
    
    opened by CodingSoot 0
Owner
gskinner team
We collaborate with smart, motivated clients to conceptualize, design, and build world-class interactive experiences.
gskinner team
A powerful official extension library of Tab/TabBar/TabView, which support to scroll ancestor or child Tabs when current is overscroll, and set scroll direction and cache extent.

extended_tabs Language: English | 中文简体 A powerful official extension library of Tab/TabBar/TabView, which support to scroll ancestor or child Tabs whe

FlutterCandies 185 Dec 13, 2022
App that shows your current location weather and forecast

Weather APP Platform: Flutter. A project that shows you the weather and the forecast for the next five days in your current location. Uses openweather

Alberto Penas Amor 9 Aug 13, 2022
null 1 Jan 20, 2022
A wrapper around Navigator 2.0 and Router/Pages to make their use a easier.

APS Navigator - App Pagination System This library is just a wrapper around Navigator 2.0 and Router/Pages API that tries to make their use easier: ??

Guilherme Silva 14 Oct 17, 2022
flutter_ssf是一个推崇使用Provider、Custom Router、dio结合的MVVM开发模式设计的Flutter应用生产级开发脚手架。

?? ?? flutter_ssf ?? ?? flutter_ssf是一个推崇使用Provider、Custom Router、dio结合的MVVM开发模式设计的Flutter应用生产级开发脚手架。 flutter_ssf只提供基本的参照组件,所以具备几乎所有业务场景中拿来即用的特性。 flutt

Assrce 11 Nov 8, 2022
A routing package that lets you navigate through guarded page stacks and URLs using the Router and Navigator's Pages API, aka "Navigator 2.0".

A Flutter package to help you handle your application routing and synchronize it with browser URL. Beamer uses the power of Router and implements all

Sandro Lovnički 485 Jan 7, 2023
Go Router example for @flutter

pub_packages Pub packages Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this is yo

Plague Fox 4 May 6, 2022
Router_generator is a flutter library for router generation

Router_generator is a flutter library for router generation

Jelly Bean 20 Sep 27, 2022
A customizable carousel slider widget in Flutter which supports inifinte scrolling, auto scrolling, custom child widget, custom animations and built-in indicators.

flutter_carousel_widget A customizable carousel slider widget in Flutter. Features Infinite Scroll Custom Child Widget Auto Play Horizontal and Vertic

NIKHIL RAJPUT 7 Nov 26, 2022
Selectable Circle where colors can be customized and a child widget can be defined

selectable_circle A Flutter package for an Circle that can be Selected with animation. How to use SelectableCircle( width: 80.0, onSelected: (

null 11 Sep 29, 2021