'Displaying notification badge on BottomNavigationBar's Icon

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?



Solution 1:[1]

Yes. It can be done by stacking two icons using the Stack and Positioned widget.

      new BottomNavigationBarItem(
        title: new Text('Home'),
        icon: new Stack(
          children: <Widget>[
            new Icon(Icons.home),
            new Positioned(  // draw a red marble
              top: 0.0,
              right: 0.0,
              child: new Icon(Icons.brightness_1, size: 8.0, 
                color: Colors.redAccent),
            )
          ]
        ),
      )

Solution 2:[2]

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

Solution 3:[3]

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: () {},
      ),
    ],
  ),
)

Solution 4:[4]

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

Solution 5:[5]

You can also nest the Stacks. For instance, if you would like to add item_count on the shopping_cart icon, you can do this:

icon: new Stack(
              children: <Widget>[
                new Icon(Icons.shopping_cart),
                new Positioned(
                  top: 1.0,
                  right: 0.0,
                  child: new Stack(
                    children: <Widget>[
                      new Icon(Icons.brightness_1,
                          size: 18.0, color: Colors.green[800]),
                      new Positioned(
                        top: 1.0,
                        right: 4.0,
                        child: new Text(item_count,
                            style: new TextStyle(
                                color: Colors.white,
                                fontSize: 15.0,
                                fontWeight: FontWeight.w500)),
                      )
                    ],
                  ),
                )
              ],
            )

Solution 6:[6]

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

Solution 7:[7]

I would use a Stack to render the marble on top of the Icon, wrapping the marble in a Positioned, Align, or FractionallySizedBox to position it the way you want.

Solution 8:[8]

        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,
                ),
              ),
            )
          ],
        )

Solution 9:[9]

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',
                ),

Solution 10:[10]

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: (){},
          ),
        ),
      ),
    ],
  ),

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 ych
Solution 3
Solution 4 dev4life
Solution 5 Anudeep
Solution 6 Nitin Mehta
Solution 7 Collin Jackson
Solution 8 Ahmed Raafat
Solution 9 Ridha Rezzag
Solution 10 ZF007