Flutter: Seamless Header Navigation from AppBar 💙

We all have added appbar in our website where we need to navigate to that section on click of a header. But have you faced issues with it? Sometimes it doesn’t navigate to the exact position, correct? Well, in this article I’ll show you how you can navigate to the exact position no matter the screen size!

Abhishek Doshi
Google Developer Experts

--

Let’s assume you have a web app that contains an appbar as follows:

Assume we have some sections like Home, About, Location, Contact and Footer and these sections have non-fixed heights or sections that don’t have the same heights. Now, upon clicking these headers, you want to navigate to respective sections at the exact position. This is something tricky because you can’t calculate how much height needs to be scrolled. So what to do? How can we scroll to the correct position? Is it even possible with Flutter? Well, well, well, let’s try something and check if it’s possible 😉

Ok so before we start the main navigation part, let’s create dummy sections as we have in the appbar. I have just created them with varied heights as follows:

So in the above code, we have added 5 containers with different heights and added a simple text in each. It looks something like the following:

Quite simple, right? As of now, we haven’t added any code for navigation. Now, to navigate to exact position, we are going to make use of Flutter’s hidden gem, GlobalKey. So let’s create a list of global keys which we will later use for navigation.

List<GlobalKey> navigatorKeys = [
GlobalKey(),
GlobalKey(),
GlobalKey(),
GlobalKey(),
GlobalKey(),
];

Now we have made this global so that we can use this list everywhere. Let’s now assign these keys to our sections. Here’s the updated code:

body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
key: navigatorKeys[0],
color: Colors.red.shade200,
height: MediaQuery.sizeOf(context).height / 3,
width: MediaQuery.sizeOf(context).width,
child: const Center(child: Text('Home Content')),
),
Container(
key: navigatorKeys[1],
color: Colors.yellow.shade200,
height: MediaQuery.sizeOf(context).height / 2,
width: MediaQuery.sizeOf(context).width,
child: const Center(child: Text('About Content')),
),
Container(
key: navigatorKeys[2],
color: Colors.blue.shade200,
height: MediaQuery.sizeOf(context).height / 4,
width: MediaQuery.sizeOf(context).width,
child: const Center(child: Text('Location')),
),
Container(
key: navigatorKeys[3],
color: Colors.green.shade200,
height: MediaQuery.sizeOf(context).height / 4,
width: MediaQuery.sizeOf(context).width,
child: const Center(child: Text('Contact')),
),
Container(
key: navigatorKeys[4],
color: Colors.pink.shade200,
height: MediaQuery.sizeOf(context).height / 5,
width: MediaQuery.sizeOf(context).width,
child: const Center(child: Text('Footer')),
),
],
),
),

So in the above code, we just assigned the navigatorKeys to the specific sections. You can make this better and more robust by using for-loop or ListView.builder.

Now it’s time to use the keys to scroll to the specific location. But for that, we need to have a scroll controller. So just create a scroll controller and assign it to your SingleChildScrollView! Along with this, also add another container so that we can scroll untilFooter. Otherwise, it will only scroll until the maximum extent 😅

Now as the next step, we need to write code (or just a function) to navigate to a specific section. The code snippet is very small:

  void scrollToSection(BuildContext context) {
Scrollable.ensureVisible(
context,
duration: const Duration(milliseconds: 600),
);
}

The above code scrolls the scrollable that encloses the given context to make the given context visible. Further, we just need to call this function. However, the context will be that of the navigator key:

scrollToSection(navigatorKeys[0].currentContext!);

The above code will navigate to the context of the widget to which the 1st navigator key is assigned!

Complete Code

Output

Summary

To summarize, we created a list of global keys and assigned it to each section. To scroll, we used Scrolable.ensureVisible that takes a context and scrolls to that particular context. Hence, we passed the context of that particular section using the key that we assigned to it (navigatorKeys[0].currentContext!). Super easy!

Hope you enjoyed this article!

Doubts? Feel free to drop a message @AbhishekDoshi26

Lazy to read the article? Here’s the GitHub Repository!

Checkout abhishekdoshi.dev for more info 💙

Don’t stop, until you are breathing!💙
- Abhishek Doshi

--

--

Abhishek Doshi
Google Developer Experts

Google Developer Expert — Dart, Flutter & Firebase 💙💛