Search code examples
androidcustomizationandroidxbottomnavigationviewandroid-bottomnav

Change size of only one icon of bottom navigation view (Android)


I want to change the size of only ONE icon (3rd icon) out of the 5 icons I have used in my bottom navigation view.

I want The Center icon big like:

My Bottom Nav View

This is what I have tried:

private fun setReportPainIconSize(){
        val bottomNavigationView =
            findViewById<BottomNavigationView>(R.id.navigationBottomView)

    val menuView: BottomNavigationMenuView =
            bottomNavigationView.getChildAt(0) as BottomNavigationMenuView
     
    val iconView: View = menuView.getChildAt(2) **//TO GET REFERENCE OF 3RD ITEM**
                    .findViewById(androidx.core.R.id.icon)
           
    val layoutParams: ViewGroup.LayoutParams = iconView.layoutParams
            val displayMetrics: DisplayMetrics = resources.displayMetrics
            layoutParams.height = TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, 47F,
                displayMetrics
            ).toInt()
            layoutParams.width = TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, 44F,
                displayMetrics
            ).toInt()
            iconView.layoutParams = layoutParams
    }

But on running my app crashes and the error message I get is :

Caused by: java.lang.NullPointerException: menuView.getChildAt(2)
     …(androidx.core.R.id.icon) must not be null

How do I accomplish it? ? Pls help!


Solution

  • Using the latest Material Design library (com.google.android.material:material:1.6.1) the id to get a reference to the menu icon View is the com.google.android.material.R.id.navigation_bar_item_icon_view

    So you can change programmatically a specific menu item size in BottomNavigationView like the below sample:

    //find the icon view for the menu item index 1
    val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavigationView)
    val menu = bottomNavigationView.menu
    val menuItem = menu.getItem(1)
    val navigationBarItemView: NavigationBarItemView = bottomNavigationView.findViewById(menuItem.itemId)
    val iconView: View = navigationBarItemView.findViewById(com.google.android.material.R.id.navigation_bar_item_icon_view)
    
    //set the new width and height for the iconView in pixels. You can change also the bottom margin of the icon View.
    val iconViewParams: FrameLayout.LayoutParams = iconView.layoutParams as FrameLayout.LayoutParams
    iconViewParams.width = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 44F, resources.displayMetrics).toInt()
    iconViewParams.height = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 47F, resources.displayMetrics).toInt()
    iconViewParams.bottomMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 35F, resources.displayMetrics).toInt()
    iconView.layoutParams = iconViewParams
    

    Also to draw something above the BottomNavigationView like the centered icon you have to make all ViewGroup parents in BottomNavigationView to have clipChildren = false and clipToPadding = false using a recursive function like the below:

    fun recursiveClipChildrenAndClipToPadding(parent: ViewGroup) {
    
        if(parent is BottomNavigationView){
            val bottomNavigationView = parent as BottomNavigationView
            bottomNavigationView.clipChildren = false
            bottomNavigationView.clipToPadding = false
        }
        for (i in 0 until parent.childCount) {
            val child = parent.getChildAt(i)
            if (child is ViewGroup) {
                val vGroup = child as ViewGroup
                vGroup.clipChildren = false
                vGroup.clipToPadding = false
                recursiveClipChildrenAndClipToPadding(vGroup)
            }
        }
    }
    

    and you have to call it like this:

    recursiveClipChildrenAndClipToPadding(bottomNavigationView)
    

    A sample result i have made using some default icons is like the below:

    custom_menu_item_position