avatarAseem Wangoo

Summary

The provided content discusses managing navigation history in Flutter Web applications using a stack data structure implemented with Dart's ListQueue and integrating custom NavigatorObservers.

Abstract

The article "Flutter Web and Navigation History" delves into the technical aspects of handling navigation history in Flutter Web applications. It emphasizes the need for a stack-like data structure to keep track of navigation routes, with the ListQueue from Dart's dart:collection library being identified as a suitable choice. The author outlines the creation of an abstract class _NavStack to define stack operations such as push, pop, top, fetchAll, and clear, which are then implemented in a concrete class NavStack. The implementation ensures that navigation actions such as adding, removing, and retrieving routes are efficient and maintain the correct order. Furthermore, the article explains how to integrate this stack with Flutter's RouteObserver by extending it and implementing didPush and didPop methods to synchronize route changes with the custom stack. This integration is achieved by adding the custom navigator observer to the navigatorObservers property of the MaterialApp widget. The article also provides visual examples and links to additional resources on Flutter Web development.

Opinions

  • The author suggests that using a stack is the most appropriate way to manage navigation history in a single-tab scenario, reflecting a common practice in web development for maintaining the order of navigation events.
  • The choice of ListQueue for implementing the stack is presented as an efficient solution, highlighting the author's preference for performance and the cyclic buffer optimization provided by this data structure.
  • By creating an abstract class for the navigation stack, the author demonstrates a commitment to software design principles, such as abstraction and encapsulation, which can lead to more maintainable and scalable code.
  • The article promotes the use of Flutter's RouteObserver as a means to seamlessly integrate custom navigation history tracking, showcasing the framework's extensibility and the author's proficiency in leveraging it.
  • The inclusion of code snippets, method explanations, and links to external documentation indicates the author's intent to provide a comprehensive guide that is both informative and practical for developers working with Flutter Web.
  • The mention of additional articles and the source code repository suggests that the author values community engagement and continuous learning within the Flutter development ecosystem.
  • The author endorses an AI service, ZAI.chat, as a cost-effective alternative to ChatGPT Plus (GPT-4), indicating a belief in the value of AI tools for developers and possibly an affiliation with the service.

Flutter Web and Navigation History

Flutter Web and Navigation History

How to know the navigation history in Flutter Web? Hmm…

All in one Flutter resource: https://flatteredwithflutter.com/flutter-web-and-navigation-history/

Begin…

View the demo here

Website: https://web.flatteredwithflutter.com/#/

We will cover briefly about

  1. Storing navigation routes
  2. Implement navigatorObservers
Flutter Web and Navigation History

1. Storing navigation routes

It's quite clear, we need a data structure for storing routes.

Thought process: When we navigate between different links in a browser, the last link is usually the first to be traced back (on click of the back button).

Flutter Web and Navigation History

Going 1 link to several

  • You navigate to link A
  • After a while, you go to link B
  • Finally, you end up at the link C

(Note: This assumes you are in 1 single tab only)

On backtracking

Flutter Web and Navigation History

Going back now

  • You start backtrack from link C
  • You go to link B
  • Finally, you end up at the link A

(Note: This assumes you are in 1 single tab only)

The data structure right for use would be Stack since we need to push the routes onto the stack and pop (when we go back to the previous link).

Stack — Push, pop, top

Implementing Stacks in Dart

In doing my research I found

dart:collection

As per the documentation:

Classes and utilities that supplement the collection support in dart:core.

But did not find any explicit collection named Stack, until I stumbled upon ListQueue

List based Queue.

Keeps a cyclic buffer of elements, and grows to a larger buffer when it fills up. This guarantees constant time peek and remove operations, and amortized constant time add operations.

The structure is efficient for any queue or stack usage.

We will use ListQueue for storing our routes.

Implementing ListQueue for storing routes

We make an abstract class first, to define the operations which we will implement for our generic ListQueue.

abstract class _NavStack<T> {
  void push(T val) {}
  void pop() {}
  T top();
  List<T> fetchAll();
  void get clear {}
}

push: For pushing a route of type T

pop: For popping the route (topmost)

top: Get the route which is on top

fetchAll: Get all the routes saved.

clear: Clear the saved routes

Let’s define our class(NavStack) which implements the above abstract class(_NavStack).

class NavStack<T> implements _NavStack<T> {}

Initialize the list queue by

final ListQueue<T> _internal = ListQueue();

Pushing item

Pushing items in this list by using the addLast function of the list queue.

_internal.addLast('SOME VALUE');

addLast: Adds the items at the end. Since each new route will be the latest, we add it to the end of the list queue.

Popping item

Pop the item in this list by using removeLast function of the list queue.

_internal.removeLast();

removeLast: Removes and returns the last element of the queue.

Top item

Getting the topmost or latest item in this list queue by the last function

_internal.last;

last: Returns the last (or topmost) element. Meaning our latest route is always at the top of the stack.

Clearing and Fetching items

We will use the clear function of the list queue for clearing our stored routes.

For fetching items, we will loop through the length of the list, add items to a new list and return.

List<T> fetchAll() {
  final _list = <T>[];
  
  for (var i = 0; i < length; i++) {
    _list.add(_internal.elementAt(i));
  }
  return _list;
}

2. Implement Navigator Observers

Flutter Web and Navigation History (Output)

We have the list queue implemented from the above step.

Next, we need to place this list queue in our flutter web, in such a way that

  • whenever a new route is pushed,
  • it should also be added to our NavStack class

There is a property inside MaterialApp called navigatorObservers. This implements RouteObserver internally.

RouteObserver

RouteObserver informs subscribers whenever a route of type R is pushed on top of their own route of type R or popped from it.

  • e.g. a RouteObserver<PageRoute> will inform subscribed RouteAwares
  • whenever the user navigates away from the current page route to another page route.

Methods inside RouteObserver class

  • didPop (whenever a route is popped)
  • didPush (whenever a route is pushed)

We will create our own navigator observers which

  • extends the RouteObserver
  • implements the didPop and didPush methods
Flutter Web and Navigation History
  • Inside the didPushwe extract the current screen name and push it into our NavStack class. This way whenever a route is pushed, it also gets added to our class.

Finally, we add this custom navigator observer to MaterialApp’s property.

return MaterialApp(
  // OTHER PROPERTIES
  navigatorObservers: [CustomRouteObserver()],
);

Interesting Articles related to Flutter Web here:

Hosted URL: https://web.flatteredwithflutter.com/#/

Source code for Flutter Web App.

Dart
Flutter
Programming
Web Development
Software Development
Recommended from ReadMedium