'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'),
),
Solution 3:[3]
Screenshot (Null safe)
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),
)
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,
),
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