Site icon Flutter Packages | Pub dev Packages – Flutter Mobile App World

A wrapper around Navigator 2.0 and Router/Pages

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:

 Basic feature set

 What we’ve tried to achieve:

 What we didn’t try to achieve:

 Overview

1 – Create the Navigator and define the routes:

final navigator = APSNavigator.from(
  routes: {
    '/dynamic_url_example{?tab}': DynamicURLPage.route,  
    '/': ...
  },
);

2 – Configure MaterialApp to use it:

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: navigator,
      routeInformationParser: navigator.parser,
    );
  }
}

3 – Create the widget Page (route):

class DynamicURLPage extends StatefulWidget {
  final int tabIndex;
  const DynamicURLPage({Key? key, required this.tabIndex}) : super(key: key);

  @override
  _DynamicURLPageState createState() => _DynamicURLPageState();

  // Builder function
  static Page route(RouteData data) {
    final tab = data.values['tab'] == 'books' ? 0 : 1;
    return MaterialPage(
      key: const ValueKey('DynamicURLPage'), // Important! Always include a key
      child: DynamicURLPage(tabIndex: tab),
    );
  }
}

4 – Navigate to it:

 APSNavigator.of(context).push(
    path: '/dynamic_url_example',
    params: {'tab': 'books'},
 );

The following sections describe better the above steps.

 Usage

1 – Creating the Navigator and defining the Routes:

final navigator = APSNavigator.from(

  // Defines the initial route - default is '/':
  initialRoute: '/dynamic_url_example', 

  //  Defines the initial route params - default is 'const {}':
  initialParams: {'tab': '1'},

  routes: {
    // Defines the location: '/static_url_example'
    '/static_url_example': PageBuilder..,

    // Defines the location (and queries): '/dynamic_url_example?tab=(tab_value)&other=(other_value)'
    // Important: Notice that the '?' is used only once 
    '/dynamic_url_example{?tab,other}': PageBuilder..,

    // Defines the location (and path variables): '/posts' and '/posts/(post_id_value)'
    '/posts': PageBuilder..,
    '/posts/{post_id}': PageBuilder..,

    // Defines the location (with path and query variables): '/path/(id_value)?q1=(q1_value)&q2=(q2_value)'.
    '/path/{id}?{?q1,q2}': PageBuilder..,

    // Defines app root - default
    '/': PageBuilder..,
  },
);

routes is just a map between Templates and Page Builders:

Given the configuration above, the app will open at: /dynamic_url_example?tab=1.

2 – Configure MaterialApp:

After creating a Navigator, we need to set it up to be used:

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: navigator,
      routeInformationParser: navigator.parser,
    );
  }
}

3 – Creating the widget Page(route):

When building a Page:

class DynamicURLPage extends StatefulWidget {
  final int tabIndex;
  const DynamicURLPage({Key? key, required this.tabIndex}) : super(key: key);

  @override
  _DynamicURLPageState createState() => _DynamicURLPageState();

  // You don't need to use a static function as Builder, 
  // but it seems to be a good way to organize things   
  static Page route(RouteData data) {
    final tab = data.values['tab'] == 'books' ? 0 : 1;
    return MaterialPage(
      key: const ValueKey('DynamicURLPage'), // Important! Always include a key
      child: DynamicURLPage(tabIndex: tab),
    );
  }
}

4 – Navigating to Pages:

Example Link: All Navigating Examples

4.1 – To navigate to a route with query variables:

 APSNavigator.of(context).push(
    path: '/dynamic_url_example',
    params: {'tab': 'books', 'other': 'abc'}, // Add query values in [params]
 );

4.2 – To navigate to a route with path variables:

 APSNavigator.of(context).push(
    path: '/post/10', // set path values in [path]
 );

4.3 – You can also include params that aren’t used as query variables:

 APSNavigator.of(context).push(
    path: '/static_url_example',
    params: {'tab': 'books'}, // It'll be added to [RouteData.values['tab']]
 );

 Details

1. Dynamic URLs Example

Example Link: Dynamic URLs Example

When using dynamic URLs, changing the app’s state also changes the browser’s URL. To do that:

  final aps = APSNavigator.of(context);
  aps.updateParams(
    params: {'tab': index == 0 ? 'books' : 'authors'},
  );
  @override
  void didUpdateWidget(DynamicURLPage oldWidget) {
    super.didUpdateWidget(oldWidget);
    final values = APSNavigator.of(context).currentConfig.values;
    tabIndex = (values['tab'] == 'books') ? 0 : 1;
  }

 What is important to know:

2. Static URLs Example

Example Link: Static URLs Example

When using static URLs, changing the app’s state doesn’t change the browser’s URL, but it’ll generate a new entry on the history. To do that:

  final aps = APSNavigator.of(context);
  aps.updateParams(
    params: {'tab': index == 0 ? 'books' : 'authors'},
  );
  @override
  void didUpdateWidget(DynamicURLPage oldWidget) {
    super.didUpdateWidget(oldWidget);
    final values = APSNavigator.of(context).currentConfig.values;
    tabIndex = (values['tab'] == 'books') ? 0 : 1;
  }

 What is important to know:

3. Return Data Example

Example Link: Return Data Example

Push a new route and wait the result:

  final selectedOption = await APSNavigator.of(context).push(
     path: '/return_data_example',
  );

Pop returning the data:

  APSNavigator.of(context).pop('Do!');

 What is important to know:

  @override
  void didUpdateWidget(HomePage oldWidget) {
    super.didUpdateWidget(oldWidget);
    final params = APSNavigator.of(context).currentConfig.values;
    result = params['result'] as String;
    if (result != null) _showSnackBar(result!);
  }

4. Multi Push

Example Link: Multi Push Example

Push a list of the Pages at once:

  APSNavigator.of(context).pushAll(
    // position: (default is at top)
    list: [
      ApsPushParam(path: '/multi_push', params: {'number': 1}),
      ApsPushParam(path: '/multi_push', params: {'number': 2}),
      ApsPushParam(path: '/multi_push', params: {'number': 3}),
      ApsPushParam(path: '/multi_push', params: {'number': 4}),
    ],
  );

In the example above ApsPushParam(path: '/multi_push', params: {'number': 4}), will be the new top.

 What is important to know:

5. Multi Remove

Example Link: Multi Remove Example

Remove all the Pages you want given a range:

  APSNavigator.of(context).removeRange(start: 2, end: 5);

6. Internal (Nested) Navigators

Example Link: Internal Navigator Example

class InternalNavigator extends StatefulWidget {
  final String initialRoute;

  const InternalNavigator({Key? key, required this.initialRoute})
      : super(key: key);

  @override
  _InternalNavigatorState createState() => _InternalNavigatorState();
}

class _InternalNavigatorState extends State<InternalNavigator> {
  late APSNavigator childNavigator = APSNavigator.from(
    parentNavigator: navigator,
    initialRoute: widget.initialRoute,
    initialParams: {'number': 1},
    routes: {
      '/tab1': Tab1Page.route,
      '/tab2': Tab2Page.route,
    },
  );

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    childNavigator.interceptBackButton(context);
  }

  @override
  Widget build(BuildContext context) {
    return Router(
      routerDelegate: childNavigator,
      backButtonDispatcher: childNavigator.backButtonDispatcher,
    );
  }
}

 What is important to know:

Warning & Suggestions

Download APS Navigator package source code on GitHub

https://github.com/guilherme-v/aps_navigator
Exit mobile version