How to use Notification Listener to change AppBar color based on scrolling position.

To change the AppBar color when the page is scrolling, we need to wrap the scrolling widget like ListView.builder with a NotificationListener widget. Then, update the state of the AppBar color on the callback function.

When we create a Flutter app we often put AppBar on the top of the page. Sometimes, there is a case when we need to change the appearance of a widget based on the scrolling position. This article will show you a useful Flutter widget called NotificationListener , which can be used to listen to various events, one of which is the scroll event.

What is NotificationListener

In Flutter, the NotificationListener widget is used to listen and respond to various system notifications during the widget lifecycle. It allows you to intercept and handle notifications that are dispatched by child widgets or the framework itself.

NotificationListener is often used in conjunction with specific subclasses of Notification to handle different types of notifications. These subclasses include:

  1. ScrollNotification: This notification is triggered when a scrollable widget is scrolled. You can use it to respond to scroll events and perform custom actions based on the scroll position or direction.
  2. GestureNotification: This notification is triggered when a gesture is detected within a widget. It provides information about the gesture, such as the type (tap, long press, etc.), the position, and the velocity. You can use it to implement custom gesture-based interactions.
  3. RouteNotification: This notification is triggered when a route change occurs in the widget hierarchy. It allows you to respond to route changes and perform actions such as updating the UI or handling navigation transitions.

In this article, we will focus on how to use ScrollNotification to change AppBar color based on a specific scroll position.

Changing the color of the AppBar widget on scrolling

To change the AppBar color when the page is scrolling, we need to wrap the scrolling widget like ListView.builder with a NotificationListener widget. Then, update the state of the AppBar color on the callback function.

Let's create a simple page containing an AppBar widget and a ListView.builder Whenever we scroll the page into a specific position, we will change the AppBar background color.

Preparation

First, let's create a new project, run this command on the terminal:

flutter create my_fancy_appbar

For simplicity replace the main.dart to be like this:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    Color appBarColor = Colors.blue;
    
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: appBarColor,
          title: const Text("My fancy appBar"),
        ),
        body: ListView.builder(
            itemCount: 100,
            itemBuilder: ((context, index) {
              return ListTile(
                leading: const Icon(Icons.notifications),
                title: Text("My fancy scrolling listview item $index"),
                trailing: const Icon(Icons.arrow_right),
              );
            })),
      ),
    );
  }
}
main.dart

Here is how the user interface looks like:

In the example above we're not adding NotificationListener yet. So, nothing happened to the AppBar when the page was scrolled, the appBar color didn't change. Let's add the  NotificationListener to make it happen.

Adding a scroll listener to change the AppBar color

To add the listener, we can wrap the ListView.builder widget with NotificationListener widget. Then, when the scroll happens we will update the appBarColor state. Notice that the AppBar uses appBarColor state as the background color. Thus, the AppBar color will change automatically when we update the state. Here is the updated code :

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Color appBarColor = Colors.blue;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: appBarColor,
          title: const Text("My fancy appBar"),
        ),
        body: NotificationListener<ScrollNotification>(
          onNotification: (ScrollNotification notification) {
            if (notification is ScrollUpdateNotification) {
              setState(() {
                appBarColor =
                    notification.metrics.pixels > 0 ? Colors.red : Colors.blue;
              });
            }

            return false;
          },
          child: ListView.builder(
              itemCount: 100,
              itemBuilder: ((context, index) {
                return ListTile(
                  leading: const Icon(Icons.notifications),
                  title: Text("My fancy scrolling listview item $index"),
                  trailing: const Icon(Icons.arrow_right),
                );
              })),
        ),
      ),
    );
  }
}
main.dart

Now, we can see the color changes when we scroll the page:

In the code above we wrap the ListView.Builder with NotificationListener<ScrollNotification> widget. The <> symbol indicates the specific type of notification that the NotificationListener will handle. In this case, it is ScrollNotification. We will discuss how to handle other types of notifications like GestureNotification and RouteNotification in some other articles.

The NotificationListener widget has a named parameter onNotification that accepts a function as its value. The function will be called when a scroll event occurs. Notice that in the code above, we pass the below function as a parameter:

(ScrollNotification notification) {
   if (notification is ScrollUpdateNotification) {
     setState(() {
        appBarColor = notification.metrics.pixels > 0 ? Colors.red : Colors.blue;
     });
}

In that function, we check whether the scroll notification type is a ScrollUpdateNotification. If it is true, then we call setState function to change the AppBar color.

There are three types/subclasses of scroll notifications:

  1. ScrollUpdateNotification : A notification that a  scrollable widget has changed its scroll position.
  2. ScrollStartNotification : A notification that a scrollable widget has started scrolling.
  3. ScrollEndNotification : A notification that a scrollable widget has stopped scrolling.

You can use those types of scroll notifications according to your needs.

If you want to know the widget's current scroll position, you can use notification.metrics.pixels like the example above. Notice that the scroll position depends on the scroll direction of your scrolling widget, whether it is horizontal or vertical. If the scroll direction is vertical, the variable shows a vertical scrolling position. It's the same thing as the horizontal scrolling position.

Conclusion

To change the AppBar color based on a scroll, we can use a NotificationListener. Wrap the scrolling widget with the NotificationListener widget, and pass a function to a named parameter called onNotification. Then, call setState from that function to update the color state of the AppBar. Thank you for reading, I hope that helps! :)