I'm trying to have a bit larger BottomNavigationView (height is a bit bigger), while also making each item icon have a top indicator that it's selected.
Something like that, but with larger height:
It's a bit hard to see it on the screenshot, but the indicator is shown at the very top of the BottomNavigationView's item, right below the BottomNavigationView's shadow.
When I set a larger height, I get each item still take smaller height, so the indicator doesn't look at the top:
Not only that, but because I used itemBackground
to set the background of each item to have the indicator, it now doesn't have the background used for the clicking effect.
About the height, I've found this question on StackOverflow, of changing the height. The only solution there is to override the library's dimensions. In this case, it's only this:
<dimen name="design_bottom_navigation_height" tools:override="true">...</dimen>
However, this only solves the issue of putting the indicator at the top.
Plus, it looks like a dirty solution, to set the dimension forcefully for the library, and as I wrote, because I used itemBackground
, it doesn't have the normal clicking effect anymore.
Here's the relevant code, modified just a bit from the wizard of Android Studio for making "Bottom Navigation Activity". The rest is the same as there :
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/container" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context=".MainActivity">
<TextView
android:id="@+id/message" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin" android:text="@string/title_home"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view" android:layout_width="0dp"
android:layout_height="@dimen/tabs_height" android:layout_marginEnd="0dp"
android:layout_marginStart="0dp" android:background="?android:attr/windowBackground" app:itemBackground="@drawable/activity_main__tab_background"
app:labelVisibilityMode="unlabeled" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu"/>
</androidx.constraintlayout.widget.ConstraintLayout>
dimens.xml
<dimen name="tabs_height">64dp</dimen>
<dimen name="design_bottom_navigation_height" tools:override="true">@dimen/tabs_height</dimen>
activity_main__tab_background.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<layer-list>
<item android:gravity="top">
<shape android:shape="rectangle">
<size android:height="2dp"/>
<solid android:color="#07a5ea"/>
</shape>
</item>
</layer-list>
</item>
</selector>
How can I have the indicator at the top, while having a larger BottomNavigationView and without losing the clicking effect?
the best solution is to change the margin of the item imageView from kotlin code on runtime here is the code
private fun navigationImagesMargin(view: View) {
if (view is ViewGroup) {
for (i in 0 until view.childCount) {
val child = view.getChildAt(i)
navigationImagesMargin(child)
}
} else if (view is ImageView) {
val param = view.layoutParams as ViewGroup.MarginLayoutParams
param.topMargin = convertDpToPx(14)
view.layoutParams = param
}
}
fun convertDpToPx(dp: Int): Int {
return Math.round(dp * (resources.displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT))
}
in the onCreate function call navigationImagesMargin
function on the BottomNavigation View
navigationImagesMargin(binding.spBottomNavigation)
but this solution requires to recall navigationImagesMargin
function everytime the view revalidated i.e. in the onItemClick listener here is the code for that
binding.spBottomNavigation.setOnNavigationItemSelectedListener { it->
binding.spBottomNavigation.post {
navigationImagesMargin(binding.spBottomNavigation)
}
true
}
in that way the images will stay where you aimed them to be on first launch
this is a link for tiny repo that include the full code https://github.com/abdulmalekDery/BottomNavigationControl