DEV Community

Haider Noor
Haider Noor

Posted on

Creating a custom AppBar in flutter

Hi!.

TL;DR -> find the source code for this here

So, I've been using flutter for some time now to develop a side project of mine. Like a lot of people, and like you probably will too, I found myself unhappy with some of the default widgets that flutter provides. In this particular case, the AppBar widget.

If you don't know, the AppBar is a widget that sits on the top of screen and usually displays the page tittle, some common actions, and the back arrow or the drawer toggle.

This is what the default looks like.

Alt Text

The problem

I needed a custom AppBar widget that received the screen title as a parameter, had custom colors, custom leading icon, and size. I also didn't want to set these variables every single time I needed an appBar.

After some time reading through several articles on how to make a custom AppBar I was still unsatisfied with the approach that most of the tutorials were suggesting. Most of the articles I found suggested creating a custom widget, like the one below, and adding it to the top of your scaffold body.

class CustomAppBar extends StatelessWidget {
  final String title;

  const CustomAppBar(
    this.title, {
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    MediaQueryData mediaQuery = MediaQuery.of(context);
    double height =
        (mediaQuery.size.height - mediaQuery.padding.top) * HEADER_HEIGHT;
    return Container(
      height: height,
      child: Row(
        children: <Widget>[
          IconButton(
            color: Colors.black,
            icon: Icon(Icons.chevron_left),
            onPressed: () => Navigator.pop(context),
          ),
          Text(title)
        ],
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

This approach works well (sort of) but I was unhappy with it because, by doing this, you forfeit a lot, if not all, of the intrinsic features and functions of the default AppBar. For example, using automaticallyImplyLeading (more info here).

Some articles also suggested adding one of the many available custom app bar libraries, but why have to manage another 3rd party library that attends to just a single use case?

My Solution

The principle is: inherit all the default AppBar and override the ones you want to customize. Simple, right?

This was my approach:

  1. Create a CustomAppBar stateless widget, that return the default AppBar, like so:

        class CustomAppBar extends StatelessWidget {
            @override
            Widget build(BuildContext context) {
                return AppBar(
                );
            }
        }
    
    

    This will allow us to add our CustomAppBar to the Scaffold in the correct way, which is:

    Scaffold(
        appBar: CustomAppBar(SCREEN_TITLE),
            body: //your body here
    )
    
  2. Add your customization to the AppBar, like for example:

    return AppBar(
        title: Text(
            title,
            style: TextStyle(color: Colors.black),
        ),
        backgroundColor: Colors.white,
        leading: IconButton(
            icon: Icon(Icons.chevron_left),
            onPressed: () => Navigator.pop(context),
            color: Colors.black,
        ),
    );
    

    If you wanted to, you could also set automaticallyImplyLeading here. In this case you would have something that looks like this:

    return AppBar(
        title: Text(
            title,
            style: TextStyle(color: Colors.black),
        ),
        backgroundColor: Colors.white,
        automaticallyImplyLeading: true,
    );
    

    Theoretically, this should be enough but there is one more step. If you go on your Scaffold and add the CustomAppBar we just created you'll get an error

    argument_type_not_assignable -> The argument type 'CustomAppBar' can't be assigned to the parameter type 'PreferredSizeWidget'
    

    This is because Scaffold doesn't actually receive AppBar in its appBar property. Instead in takes in PreferredSizeWidget. So we need an extra step.

  3. Extend PreferredSizeWidget. This is where you set the custom height of your CustomAppBar.

    You will have to edit your constructor to account for this change. In the end, you should have something similar to this:

    
    class CustomAppBar extends StatelessWidget with PreferredSizeWidget {
        @override
        final Size preferredSize;
    
        final String title;
    
        CustomAppBar(
            this.title,
            { Key key,}) : preferredSize = Size.fromHeight(50.0),
                super(key: key);
    
        @override
        Widget build(BuildContext context) {
            return AppBar(
                title: Text(
                    title,
                    style: TextStyle(color: Colors.black),
                ),
                backgroundColor: Colors.white,
                automaticallyImplyLeading: true,
            );
        }
    }
    
    

conclusion

By doing this I got my custom AppBar with all the customization I wanted without adding any 3rd party library. :) and this is what the end product looks like.

Alt Text

Let me know if you have a better way to do this.

Hug

Top comments (7)

Collapse
 
antonyleons profile image
Antony Leons

Quality post. you may want to mention titleSpacing to adjust the spacing between the back icon and the text.

AppBar(
      titleSpacing: 0,)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ncuillery profile image
Nicolas Cuillery

Thanks, that was helpful 👍

Collapse
 
nipunravisara profile image
Nipun Ravisara

This is great Thanks!

Collapse
 
cholasimmons profile image
Chola

Outstanding! Thanks so much you saved me so much time

Collapse
 
byvak profile image
Byvak

Very useful post ! Thanks

Collapse
 
zyllus17 profile image
Maruf Hassan

Great post!

Collapse
 
itsramy profile image
itsRammy

What should it be written instead of " SCREEN_TITLE" ?