Displaying notification badge on BottomNavigationBar's Icon

Viewed 62431

I'd like to display notification badge (a colored marble) on the top right corner of BottomNavigationBar's Icon widget when a new message has arrived in the inbox tab. It is similar to https://developer.android.com/preview/features/notification-badges.html but for my case it is displayed in-app.

Any tips to paint the overlay on existing icon to create a custom Icon class?

10 Answers

One more variation of counting badge (implemented with Stack of Icon and wrapped in Container Text, which stretched when counter increase):

BottomNavigationBarItem(
  icon: new Stack(
    children: <Widget>[
      new Icon(Icons.notifications),
      new Positioned(
        right: 0,
        child: new Container(
          padding: EdgeInsets.all(1),
          decoration: new BoxDecoration(
            color: Colors.red,
            borderRadius: BorderRadius.circular(6),
          ),
          constraints: BoxConstraints(
            minWidth: 12,
            minHeight: 12,
          ),
          child: new Text(
            '$_counter',
            style: new TextStyle(
              color: Colors.white,
              fontSize: 8,
            ),
            textAlign: TextAlign.center,
          ),
        ),
      )
    ],
  ),
  title: Text('Notifications'),
),

BottomNavigationBar item counting badge

Screenshot (Null safe)

enter image description here

If you also want to handle onTap with some splash, use this widget, you can further customize it according to your needs:

You don't need to depend on a package, just copy this class:

class NamedIcon extends StatelessWidget {
  final IconData iconData;
  final String text;
  final VoidCallback? onTap;
  final int notificationCount;

  const NamedIcon({
    Key? key,
    this.onTap,
    required this.text,
    required this.iconData,
    this.notificationCount = 0,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: onTap,
      child: Container(
        width: 72,
        padding: const EdgeInsets.symmetric(horizontal: 8),
        child: Stack(
          alignment: Alignment.center,
          children: [
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Icon(iconData),
                Text(text, overflow: TextOverflow.ellipsis),
              ],
            ),
            Positioned(
              top: 0,
              right: 0,
              child: Container(
                padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
                decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.red),
                alignment: Alignment.center,
                child: Text('$notificationCount'),
              ),
            )
          ],
        ),
      ),
    );
  }
}

Usage:

Scaffold(
  appBar: AppBar(
    title: Text('AppBar'),
    actions: [
      NamedIcon(
        text: 'Inbox',
        iconData: Icons.notifications,
        notificationCount: 11,
        onTap: () {},
      ),
      NamedIcon(
        text: 'Mails',
        iconData: Icons.mail,
        notificationCount: 1,
        onTap: () {},
      ),
    ],
  ),
)

There is a nice package[0] that makes this as simple as using the following instead of an Icon:

Badge(
  badgeContent: Text('3'),
  child: Icon(Icons.settings),
)

0: https://pub.dev/packages/badges

new BottomNavigationBar(
      type: BottomNavigationBarType.fixed,
      fixedColor: const Color(0xFF2845E7),
      items: [
        new BottomNavigationBarItem(
          icon: new Icon(
            Icons.home,
          ),
          title: new Text(
            "Home",
          ),
        ),
        new BottomNavigationBarItem(
            icon: new Icon(
              Icons.call,
            ),
            title: new Text(
              "Calls",
            )),
        new BottomNavigationBarItem(
            icon: new Icon(
              Icons.camera_alt,
            ),
            title: new Text(
              "Camera",
            )),
        new BottomNavigationBarItem(
            icon: new Stack(children: <Widget>[
              new Icon(Icons.favorite),
              new Positioned(
                  top: -1.0,
                  right: -1.0,
                  child: new Stack(
                    children: <Widget>[
                      new Icon(
                        Icons.brightness_1,
                        size: 12.0,
                        color: const Color(0xFF2845E7),
                      ),
                    ],
                  ))
            ]),
            title: new Text(
              "Stories",
            )),
        new BottomNavigationBarItem(
            icon: new Icon(
              Icons.account_circle,
            ),
            title: new Text(
              "Contacts",
            )),
      ],
      onTap: (){},
      currentIndex: 0,
    ),

BottomNavigationBar with notification badge on favorite icon

        Stack(
          children: <Widget>[
            IconButton(
              iconSize: 32,
              splashColor: Colors.transparent,
              highlightColor: Colors.transparent,
              padding: EdgeInsets.zero,
              constraints: BoxConstraints(),
              icon: Icon(Icons.notifications,color: AshtarColors.dark_blue,),
              onPressed: () {
                log("notification");
              },
            ),
            new Positioned(
              top: 3,
              right: 0,
              child: new Container(
                padding: EdgeInsets.all(1),
                decoration: new BoxDecoration(
                  color: Colors.red,
                  borderRadius: BorderRadius.circular(6),
                ),
                constraints: BoxConstraints(
                  minWidth: 15,
                  minHeight: 15,
                ),
                child: new Text('11',
                  style: new TextStyle(
                    color: Colors.white,
                    fontSize: 11,
                  ),
                  textAlign: TextAlign.center,
                ),
              ),
            )
          ],
        )

Before Feb 2022, I have been using the Stack widget, but lately I start using Badges Package after flutter team talked about it in the widget of the week series it makes thing easier and simple: video from flutter YouTube channel

the package: Badges for Flutter

example:

                 BottomNavigationBarItem(
                  icon: Badge(
                    showBadge: true,
                    badgeContent: Text('6', style: const TextStyle(color: Colors.white)),
                    animationType:  BadgeAnimationType.scale,
                    shape: BadgeShape.circle,
                    //position: BadgePosition.center(),
                    child: const Icon(Icons.notifications),
                  ),
                  label: 'Notifications',
                ),

Transparent appBar without navigation icon and bell icon:

appBar: AppBar(
    backgroundColor: Colors.transparent,
    automaticallyImplyLeading: false,
    title: Align(
      alignment: Alignment.centerLeft,
      child: Text('Find Your Favorite drink',
        style: kTitle,
      ),
    ),
    actions: [
      Padding(
        padding: const EdgeInsets.only(right: 12.0,top: 5,bottom: 5),
        child: Container(
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(15),
          ),
          height: 20,
          width: 45,
          child: IconButton(
            icon: Stack(
                children: <Widget>[
                  new Icon(Icons.notifications_none_outlined,
                    color: Color(0xFFFEA70B),
                  ),
                  new Positioned(  // draw a red marble
                    top: 0.0,
                    right: 0.0,
                    child: new Icon(Icons.brightness_1, size: 8.0,
                        color: Color(0xFFFF4545)),
                  )
                ]
            ),
            onPressed: (){},
          ),
        ),
      ),
    ],
  ),
Related