Home » Android » android – Is there a way to display notification badge on Google's official BottomNavigationView menu items introduced in API 25?

android – Is there a way to display notification badge on Google's official BottomNavigationView menu items introduced in API 25?

Posted by: admin May 14, 2020 Leave a comment

Questions:

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 one of the menu items in bottom navigation bar.

I have a selector drawable where I have added checked true and checked false states with greyed out drawable which has a BLUE dot on it. When user navigates to other navigation item the whole menu button turns grey and the badge as well. I know this is because itemIconTint is applied to the drawable which is the reason having a different colour badge as part of the icon won’t work. Is there any alternate way to achieve this?

<android.support.design.widget.BottomNavigationView
    android:id="@+id/bottom_navigation"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="@color/white"
    app:itemIconTint="@color/selector_bottom_nav"
    app:itemTextColor="@color/selector_bottom_nav"
    android:layout_gravity="bottom"
    app:menu="@menu/menu_bottom_nav">
</android.support.design.widget.BottomNavigationView>

That is how I am using it. Removing itemIconTint and changing icon drawable programmatically does not help.

On Android Developers I have found nothing and it being pretty new nothing is available on the web as well.

There are custom libraries for bottom navigation bar but I am looking for its support in the official one.

Any ideas, anyone?

How to&Answers:

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.

Answer:

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);
    }
}

Answer:

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