I have been trying BottomNavigationView
released in API 25. I want to display a notification badge (say a small blue circle with or without a count in it) on on
Answering my own question:
I ended up putting 2 ImageViews
with badge drawable and visiblity GONE
in my layout. I calculate positioning of the badges like this:
private void calculateBadgesPosition() {
int totalNavItems = 3;
for(int i = 0 ; i < bottomNavigation.getChildCount() ; i++) {
View view = bottomNavigation.getChildAt(i);
// Since Y remains same for all badges at least in my case.
// 1.3 is a factor that fits my placement of badge.
double y = getResources().getDisplayMetrics().heightPixels - (view.getMeasuredHeight() * 1.3);
if(image2ndItemBadge != null) {
float x = getResources().getDisplayMetrics().widthPixels/2 + imageClassroomBadge.getMeasuredWidth()/2;
image2ndItemBadge.setX(x);
image2ndItemBadge.setY((float)y);
image2ndItemBadge.requestLayout();
}
// Since BottomNavigationView items are equally distributed you can find
// the right position for 3rd item (in my case last item) by dividing
// BottomNavigationView width by 3 and then by 2 to get the middle of that
// item, which was needed in my case.
if(image3rdItemBadge != null) {
float x = getResources().getDisplayMetrics().widthPixels - ((view.getMeasuredWidth()/totalNavItems)/2);
image3rdItemBadge.setX(x);
image3rdItemBadge.setY((float)y);
image3rdItemBadge.requestLayout();
}
// BottomNavigationView count should always be 1
// but I observed the count was 2 in API 19. So I break after first iteration.
break;
}
}
You can remove the for loop and just check if child count greater than 0 and get that child. I call the above method at the end of onCreate like this:
ViewTreeObserver viewTreeObserver = getWindow().getDecorView().getViewTreeObserver();
viewTreeObservier.addOnGlobalLayoutListener (new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
calculateBadgesPosition();
getWindow().getDecorView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
Badge ImageView
not being part of the BottomNavigationView
Items drawable will not be effected by tint that BottomNavigationView
applies on selection/un selection of item. Also if you see your badge not appearing try giving it a higher elevation
8 or 16 or whatever. In my case my badge stayed behind BottomNavigationView
probably because it has higher elevation or Z index.
I tested this with 3 different screen sizes and the positioning was same on all.
I hope this helps anyone facing similar issue with official BottomNavigationView
.
Also if you have a better approach please share it.
Create a layout with a Textview.
Inflate the view by adding the BottomNavigationMenuView as child for BottomNavigationView. Add the count to required menu.
See the below link.
https://stackoverflow.com/a/48269868/4675067
One way of achieving this is using two icons for each item - one with the badge and the other without and replace them programmatically. Alternatively, instead of two icons, you can use a single icon and draw the badge programmatically. So the code can look something like this (assuming you know the index of each item and can get the Drawable
for each):
public static void updateItem(BottomNavigationView bottomNavigationView, int index, Drawable icon) {
Menu menu = bottomNavigationView.getMenu();
MenuItem item = menu.getItem(index);
if (item != null) {
item.setIcon(icon);
}
}