Search code examples
androidkotlinbottomnavigationviewandroid-bottom-nav-view

Add ring around selected tab in BottomNavigationView


Is there a way to put a ring around a selected tab using BottomNavigationView the way Instagram does when you click on the profile tab?

In this case, the profile tab has a gray ring around the photo.

enter image description here


Solution

  • You'd set the app:itemBackground with a checked state selector with centered oval shape

    Selector: drawable/rounded_selector:

    <?xml version="1.0" encoding="utf-8"?>
    
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_checked="true">
            <layer-list>
                <item android:gravity="center">
                    <shape android:shape="oval">
                        <size android:width="35dp" android:height="35dp" />
                        <stroke android:width="3dp" android:color="@android:color/darker_gray" />
                    </shape>
                </item>
            </layer-list>
        </item>
    </selector>
    

    And set that to the BottomNavigationView:

    <com.google.android.material.bottomnavigation.BottomNavigationView
        ...
        app:itemBackground="@drawable/rounded_selector"
        app:labelVisibilityMode="unlabeled" />
    


    Edit

    How would you do it if you wanted only one of the tabs to show the circle selector? The way Instagram does it only for the profile.

    You'd set that to the menu item by combining drawable layers into LayerDrawable, then set that back to the menu item:

    drawable/circle_border

    <?xml version="1.0" encoding="utf-8"?>
    
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval">
        <stroke android:width="8dp" />
        <solid android:color="@android:color/transparent" />
        <size
            android:width="200dp"
            android:height="200dp" />
    </shape>
    

    And in code:

    val item = bottomNavView.menu.findItem(R.id.profile_item) // change to the id of the profile item
    
    val border = ResourcesCompat.getDrawable(
        resources,
        R.drawable.circle_border, null
    ) as GradientDrawable
    val layerDrawable = LayerDrawable(arrayOf(item.icon, border))
    item.icon = layerDrawable