Buscar pacotes, repositórios e categorias de apps

Detalhes do pacotev1.1.1

routemaster

Navegador fácil de usar para web, mobile e desktop no Flutter. Roteamento baseado em URL, navegação simples de abas e rotas aninhadas.

AndroidiOSWebmacOSWindowsLinux
Downloads em 30 dias
5,9 mil
Curtidas
712
Pontos Pub
140

Instalar pacote

flutter pub add routemaster

Visão geral do pacote

Orientação gerada a partir de informações públicas. Apenas para referência.

Routemaster é uma solução leve e fácil de usar para roteamento em aplicativos Flutter para web, mobile e desktop. Permite navegação baseada em URL com suporte a rotas aninhadas e navegação por guias, simplificando o gerenciamento de rotas complexas. Criado com simplicidade e experiência do desenvolvedor em mente, o Routemaster se integra perfeitamente a projetos existentes do Flutter. Sua API limpa permite manipular transições de rota, parâmetros dinâmicos e links profundos de forma intuitiva. Ideal para aplicativos que exigem navegação estruturada sem código boilerplate.

Casos de uso

  • Aplicações de página única com conteúdo dinâmico
  • Interfaces multi-folha em dispositivos móveis e na web
  • Estruturas de rota aninhadas em interfaces complexas
  • Linking profundo e sincronização de URL
  • Aplicativos multiplataforma que precisam de roteamento consistente
  • Navegação simples com configuração mínima

Principais recursos

  • Roteamento baseado em URL
  • Suporte para rotas aninhadas e com guias
  • Boilerplate mínimo
  • Compatibilidade multiplataforma
  • Integração fácil com aplicativos Flutter existentes
  • Parâmetros de rota dinâmicos

Indicado para

  • Desenvolvedores construindo aplicativos cross-platform com Flutter
  • Equipes que priorizam uma lógica de roteamento limpa e sustentável
  • Projetos que exigem links profundos ou comportamento semelhante a SPA
  • Aplicativos com hierarquias de navegação complexas
  • Iniciantes procurando uma solução intuitiva de roteamento

Considerações

  • Limitado ao modelo nativo de navegação do Flutter
  • Pode exigir gerenciamento adicional de estado para casos de uso avançados
  • Não ideal para comportamentos de roteamento altamente personalizados além dos padrões padrão
  • Sem suporte embutido para guardas de rota ou redirecionamentos de autenticação

README original

Snapshot do README original do repositório-fonte vinculado. Consulte o repositório para o conteúdo mais recente.

Routemaster

Hello! Routemaster is an easy-to-use router for Flutter, which wraps over Flutter's Router API.

Build codecov pub

Features

  • Simple declarative mapping from URLs to pages
  • Easy-to-use API: just Routemaster.of(context).push('/page')
  • Really easy nested navigation support for tabs
  • Multiple route maps: for example one for a logged in user, another for logged out
  • Observers to easily listen to route changes
  • Covered by over 250 unit, widget and integration tests

Here's the entire routing setup needed for an app featuring tabs and pushed routes:

final routes = RouteMap(
  routes: {
    '/': (_) => CupertinoTabPage(
          child: HomePage(),
          paths: ['/feed', '/settings'],
        ),

    '/feed': (_) => MaterialPage(child: FeedPage()),
    '/settings': (_) => MaterialPage(child: SettingsPage()),
    '/feed/profile/:id': (info) => MaterialPage(
      child: ProfilePage(id: info.pathParameters['id'])
    ),
  }
);

void main() {
  runApp(
      MaterialApp.router(
        routerDelegate: RoutemasterDelegate(routesBuilder: (context) => routes),
        routeInformationParser: RoutemasterParser(),
      ),
  );
}

And then to navigate:

Routemaster.of(context).push('/feed/profile/1');

...you can see this in action in this simple app example.

There's also a more advanced example.

I would love any feedback you have! Please create an issue for API feedback.

Documentation

Begin with the quick start below, but also see the API reference, wiki and FAQs.


Quick start API tour

Overview

Routemaster generates pages based on the current path. This is the key concept of its path-base routing. Path structure matters.

It uses the path to decide where a page should be pushed. This means the path needs to match your intended page hierarchy.

For example:

'/tabs': (route) => TabPage(child: HomePage(), paths: ['one', 'two']),

// First tab default page
'/tabs/one': (route) => MaterialPage(child: TabOnePage()),

// Second tab default page
'/tabs/two': (route) => MaterialPage(child: TabTwoPage()),

// Second tab sub-page: will be displayed in the 2nd tab because it
// starts with '/tabs/two'
'/tabs/two/subpage': (route) => MaterialPage(child: TabTwoPage()),

// Not a tab page: will not be displayed in in a tab
// because the path doesn't start with '/tabs/one' or '/tabs/two'
'/tabs/notInATab': (route) => MaterialPage(child: NotTabPage()),

Any child paths that begin with /tabs/one or /tabs/two will be pushed into the correct tab.

When navigating to /tabs/two/subpage, the TabPage will be asked "hey, do you know how to handle this path?" and it'll go "sure! it starts with /tabs/two, so it goes in my second tab".

However, navigating to /tabs/notInATab will not be displayed in a tab, but pushed on top of the tab bar.

TabPage will be all "yeah sorry, no idea what to do with that, doesn't match any of my tab paths" and its parent will be asked to hande it.

Path hierarchy matters, for example changing where dialogs are displayed.

Routing

Basic app routing setup
MaterialApp.router(
  routerDelegate: RoutemasterDelegate(
    routesBuilder: (context) => RouteMap(routes: {
      '/': (routeData) => MaterialPage(child: PageOne()),
      '/two': (routeData) => MaterialPage(child: PageTwo()),
    }),
  ),
  routeInformationParser: RoutemasterParser(),
)
Navigate from within pages
Routemaster.of(context).push('relative-path');
Routemaster.of(context).push('/absolute-path');

Routemaster.of(context).replace('relative-path');
Routemaster.of(context).replace('/absolute-path');
Path parameters
// Path '/products/123' will result in ProductPage(id: '123')
RouteMap(routes: {
  '/products/:id': (route) => MaterialPage(
        child: ProductPage(id: route.pathParameters['id']),
      ),
  '/products/myPage': (route) => MaterialPage(MyPage()),
})

Note that routes without path parameters have priority, so in the above example /products/myPage will show MyPage.

Query parameters
// Path '/search?query=hello' results in SearchPage(query: 'hello')
RouteMap(routes: {
  '/search': (route) => MaterialPage(
        child: SearchPage(query: route.queryParameters['query']),
      ),
})
Get current path info within a widget
RouteData.of(context).path; // Full path: '/product/123?query=param'
RouteData.of(context).pathParameters; // Map: {'id': '123'}
RouteData.of(context).queryParameters; // Map: {'query': 'param'}

Tabs

Setup:

RouteMap(
  routes: {
    '/': (route) => TabPage(
          child: HomePage(),
          paths: ['/feed', '/settings'],
        ),
    '/feed': (route) => MaterialPage(child: FeedPage()),
    '/settings': (route) => MaterialPage(child: SettingsPage()),
  },
)

Main page:

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final tabPage = TabPage.of(context);

    return Scaffold(
      appBar: AppBar(
        bottom: TabBar(
          controller: tabPage.controller,
          tabs: [
            Tab(text: 'Feed'),
            Tab(text: 'Settings'),
          ],
        ),
      ),
      body: TabBarView(
        controller: tabPage.controller,
        children: [
          for (final stack in tabPage.stacks) PageStackNavigator(stack: stack),
        ],
      ),
    );
  }
}

Cupertino tabs

Setup:

RouteMap(
  routes: {
    '/': (route) => CupertinoTabPage(
          child: HomePage(),
          paths: ['/feed', '/settings'],
        ),
    '/feed': (route) => MaterialPage(child: FeedPage()),
    '/settings': (route) => MaterialPage(child: SettingsPage()),
  },
)

Main page:

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final tabState = CupertinoTabPage.of(context);

    return CupertinoTabScaffold(
      controller: tabState.controller,
      tabBuilder: tabState.tabBuilder,
      tabBar: CupertinoTabBar(
        items: [
          BottomNavigationBarItem(
            label: 'Feed',
            icon: Icon(CupertinoIcons.list_bullet),
          ),
          BottomNavigationBarItem(
            label: 'Settings',
            icon: Icon(CupertinoIcons.search),
          ),
        ],
      ),
    );
  }
}

Guarded routes

Show default not found page if validation fails:

'/protected-route': (route) => 
    canUserAccessPage()
      ? MaterialPage(child: ProtectedPage())
      : NotFound()

Redirect to another page if validation fails (changes URL):

'/protected-route': (route) => 
    canUserAccessPage()
      ? MaterialPage(child: ProtectedPage())
      : Redirect('/no-access'),

Show another page if validation fails (doesn't change URL):

'/protected-route': (route) => 
    canUserAccessPage()
      ? MaterialPage(child: ProtectedPage())
      : MaterialPage(child: CustomNoAccessPage())

404 Page

Default page to shown on unknown URL:

RouteMap(
    onUnknownRoute: (route, context) {
        return MaterialPage(child: NotFoundPage());
    },
    routes: {
        '/': (_) => MaterialPage(child: HomePage()),
    },
)

Redirect

Redirect one route to another:

RouteMap(routes: {
    '/one': (routeData) => MaterialPage(child: PageOne()),
    '/two': (routeData) => Redirect('/one'),
})

Redirect all routes to login page, for a logged-out route map:

RouteMap(
  onUnknownRoute: (_) => Redirect('/'),
  routes: {
    '/': (_) => MaterialPage(child: LoginPage()),
  },
)

Passing path parameters from original to the redirect path:

RouteMap(routes: {
    '/user/:id': (routeData) => MaterialPage(child: UserPage(id: id)),
    '/profile/:uid': (routeData) => Redirect('/user/:uid'),
})

Swap routing map

You can swap the entire routing map at runtime.

This is particularly useful for different pages depending on whether the user is logged in:

final loggedOutMap = RouteMap(
  onUnknownRoute: (route, context) => Redirect('/'),
  routes: {
    '/': (_) => MaterialPage(child: LoginPage()),
  },
);

final loggedInMap = RouteMap(
  routes: {
    // Regular app routes
  },
);

MaterialApp.router(
  routerDelegate: RoutemasterDelegate(
    routesBuilder: (context) {
			// This will rebuild when AppState changes
      final appState = Provider.of<AppState>(context);
      return appState.isLoggedIn ? loggedInMap : loggedOutMap;
    },
  ),
  routeInformationParser: RoutemasterParser(),
);

Navigation observers

class MyObserver extends RoutemasterObserver {
	// RoutemasterObserver extends NavigatorObserver and
	// receives all nested Navigator events
  @override
  void didPop(Route route, Route? previousRoute) {
    print('Popped a route');
  }

	// Routemaster-specific observer method
  @override
  void didChangeRoute(RouteData routeData, Page page) {
    print('New route: ${routeData.path}');
  }
}

MaterialApp.router(
  routerDelegate: RoutemasterDelegate(
    observers: [MyObserver()],
    routesBuilder: (_) => routeMap,
  ),
  routeInformationParser: RoutemasterParser(),
);

Navigate without a context

app.dart

final routemaster = RoutemasterDelegate(
  routesBuilder: (context) => routeMap,
);

MaterialApp.router(
  routerDelegate: routemaster,
  routeInformationParser: RoutemasterParser(),
)

my_widget.dart

import 'app.dart';

void onTap() {
  routemaster.push('/blah');
}

Hero animations

Hero animations will work automatically on the top-level navigator (assuming you're using MaterialApp or CupertinoApp).

For any child navigators, you'll need to wrap PageStackNavigator in a HeroControllerScope, like this:

HeroControllerScope(
  controller: MaterialApp.createMaterialHeroController(),
  child: PageStackNavigator(
    stack: pageStack,
  )
)

Design goals

  • Integrated: work with the Flutter Router API, don't try to replace it. Try to have a very Flutter-like API.
  • Usable: design around user scenarios/stories, such as the ones in the Flutter storyboard - see here for examples.
  • Opinionated: don't provide 10 options to achieve a goal, but be flexible for all scenarios.
  • Focused: just navigation, nothing else. For example, no dependency injection.

This project builds on page_router.

Categorias

Dependências

Lista de dependências 3 itens

Repositório-fonte

Projetos que usam este pacote

Rankings