11

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?

Rodia
  • 1,407
  • 8
  • 22
  • 29
Waqas
  • 151
  • 1
  • 8

3 Answers3

3

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.

SocialSupaCrew
  • 464
  • 2
  • 9
  • 14
Waqas
  • 151
  • 1
  • 8
0

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);
    }
}
Doron Yakovlev Golani
  • 5,188
  • 9
  • 36
  • 60
  • Thank you for answering. Like I have mentioned in the question, changing drawable programmatically does not help. I already have different drawables but as long as user clicks other menu item in the BottomNavigationView greyish tint is applied to the drawable. showing the item is not selected anymore. That tint applies by default and to the whole image so badge becomes grey as well. – Waqas Feb 22 '17 at 18:39
0

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

Abish R
  • 1,537
  • 3
  • 18
  • 36