151

BottomNavigationView doesn't show menu's title that are inactive.

How to show titles of all menu elements in bottomNavigationBar? The problem is that in my case shown only title of element that is clicked.

enter image description here

Natan Rubinstein
  • 1,873
  • 3
  • 11
  • 13

21 Answers21

335

Implementation of BottomNavigationView has condition: when there is more than 3 items then use shift mode.

At this moment you cannot change it through existing API and the only way to disable shift mode is to use reflection.

You'll need helper class:

import android.support.design.internal.BottomNavigationItemView;
import android.support.design.internal.BottomNavigationMenuView;
import android.support.design.widget.BottomNavigationView;
import android.util.Log;
import java.lang.reflect.Field;

public class BottomNavigationViewHelper {
    public static void disableShiftMode(BottomNavigationView view) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
        try {
            Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
            shiftingMode.setAccessible(true);
            shiftingMode.setBoolean(menuView, false);
            shiftingMode.setAccessible(false);
            for (int i = 0; i < menuView.getChildCount(); i++) {
                BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
                //noinspection RestrictedApi
                item.setShiftingMode(false);
                // set once again checked value, so view will be updated
                //noinspection RestrictedApi
                item.setChecked(item.getItemData().isChecked());
            }
        } catch (NoSuchFieldException e) {
            Log.e("BNVHelper", "Unable to get shift mode field", e);
        } catch (IllegalAccessException e) {
            Log.e("BNVHelper", "Unable to change value of shift mode", e);
        }
    }
}

And then apply disableShiftMode method on your BottomNavigationView, but remember if you are inflating menu view from your code, you have to execute it after inflating.

Example usage:

BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation_bar);
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);

PS.

Remember, you'll need to execute this method each time you change menu items in your BottomNavigationView.

UPDATE

You also need to update proguard configuration file (e.g. proguard-rules.pro), code above uses reflection and won't work if proguard obfuscate the mShiftingMode field.

-keepclassmembers class android.support.design.internal.BottomNavigationMenuView { 
    boolean mShiftingMode; 
}

Thanks Muhammad Alfaifi for pointing this issue and providing snippet.

UPDATE 2

As Jolanda Verhoef pointed out the new Support library (28.0.0-alpha1) and also the new Material Components library (1.0.0-beta01) offers a public property which can be used to manipulate the shifting mode over 3 menu items.

<com.google.android.material.bottomnavigation.BottomNavigationView
    ...
    app:labelVisibilityMode="labeled"
    ... 
/>

In Material Components library it also applies if there are 5 menu items.

UPDATE 3

As @ThomasSunderland also pointed out, you can set this property to false app:itemHorizontalTranslation="false" without Enabled postfix to disable shifting animation.

you can check the full guide to styling the BottomNavigation here

mochadwi
  • 1,190
  • 9
  • 32
  • 87
  • 17
    The field will be obfuscated so no way to change its value unless you exclude it in your proguard-rules file – Muhammad Alfaifi Dec 28 '16 at 10:21
  • Good catch! I will later update the answer with sample proguard configuration. – Przemysław Piechota. kibao Dec 28 '16 at 10:40
  • 8
    -keepclassmembers class android.support.design.internal.BottomNavigationMenuView { boolean mShiftingMode; } – Muhammad Alfaifi Dec 28 '16 at 10:51
  • 1
    Just complementing this answer, as I had some doubts first impression: You can replace Timber by Log (pretty obvious) and proguard is file, named proguard-rules.pro, which you just need to add the code below update. Sync build.gradle and it's ready to go. Thanks @PrzemysławPiechota.kibao and MuhammadAlfaifi – Victor Oliveira Dec 28 '16 at 21:52
  • 8
    Sometimes, I really wonder why Google forces it's view implementations on developers. While there are 4 options on the Google+ app itself, this simple feature should have been accessible via a simple function if available! Similar issue was there with the TabLayout which was fixed a lot later in support library. Thanks for that workaround to Original Replier and @MuhammadAlfaifi for improving this. – sud007 May 12 '17 at 05:28
  • 2
    it works perfectly!! I wish that the `BottomNavigationView` had the option to toggle it without the need for reflection – Shujito Jul 09 '17 at 17:27
  • 1
    Hopefully google will soon release [this version](https://github.com/material-components/material-components-android/blob/master/lib/src/android/support/design/widget/BottomNavigationView.java) of the BottomNavigationView which includes a method to setShiftingMode both in xml and java. – MidasLefko Oct 22 '17 at 11:15
  • Have in mind that if you fast click through the tabs the font or icon color will change – Oya Nov 07 '17 at 14:03
  • @MuhammadAlfaifi Great stuff. The proguard was causing the problem in upgrade scenario which got fixed by the rules. – reactivedroid Feb 19 '18 at 07:59
  • @PrzemysławPiechota.kibao, it's not gonna work on Android P, isn't it? https://developer.android.com/preview/restrictions-non-sdk-interfaces.html – Yazazzello Apr 25 '18 at 08:15
  • @Yazazzello It should work on Android P, because the BottomNavigationView is from support library, not from Android SDK. Restrictions will be on non-SDK interfaces from packages listed at https://developer.android.com/reference/packages.html – Przemysław Piechota. kibao Apr 25 '18 at 09:42
  • 20
    The new support library (28.0.0-alpha1) supports changing this behavior through app:labelVisibilityMode="labeled" – Jolanda Verhoef May 01 '18 at 11:33
  • 1
    The comment of Jolanda Verhoef should be included in the answer as Android P has marked this as a private API and the reflection method does not work anymore. – peshkira Jun 08 '18 at 10:34
  • For me, I had to following to make it work. val bottomNavigationView: BottomNavigationView = findViewById < BottomNavigationView >(R.id.navigation) BottomNavigationViewHelper.disableShiftMode(bottomNavigationView) – diehard98 Jun 23 '18 at 12:28
  • 3
    In addition to Jolanda Verhoef, when you use 5 icons the shifting occurs again. But now there is a method called setItemHorizontalTranslationEnabled. Setting this to false keep the icons in their place. – KvdLingen Jul 04 '18 at 08:52
  • The setItemHorizontalTranslationEnabled() method can be set in xml with the property app:itemHorizontalTranslationEnabled="false" if you want to disable the shifting animation – Thomas Sunderland Jul 31 '18 at 01:28
  • 28.0.0 support library changed shifting behavior. You can set this style on your BottomNavigationView if you’d like a bottom navigation bar with the old behavior. style="@style/Widget.Design.BottomNavigationView" – Mikhail Sharin Oct 16 '18 at 07:47
  • I can't edit your answer, but FYI: library 28.0.1-alpha1 doesn't exist. Use 28.0.0-alpha1 to use labelVisibilityMode. – saltandpepper Oct 18 '18 at 10:14
  • @ThomasSunderland you might want to change it to `app:itemHorizontalTranslation="false"` for 28.0.0-alpha1, so you can use `app:labelVisibilityMode="labeled"` as well combined with proguard configuration to keep the variable name. References here: https://mikescamell.com/bottoms-up-bottomnavigationview-updates-in-the-material-design-design-support-library/index.html – mochadwi Mar 31 '19 at 13:44
55

Since support library 28.0.0-alpha1:

<android.support.design.widget.BottomNavigationView
    app:labelVisibilityMode="labeled" />
svkaka
  • 3,942
  • 2
  • 31
  • 55
Junbin Deng
  • 651
  • 5
  • 6
30

To disable the text animation you can also use this in your dimens.xml file:

<dimen name="design_bottom_navigation_active_text_size">12sp</dimen>

You might also need to add this in your manifest :

tools:override="true"
Pafoid
  • 435
  • 4
  • 8
24

You can now use app:labelVisibilityMode="[labeled, unlabeled, selected, auto]" in 28-alpha

  • labeled will keep all labels visible.
  • unlabeled will show only icons.
  • selected will only show the label for the selected item and shift items.
  • auto will choose labeled or selected based on the number of items you have. labeled for 1-3 items and selected for 3+ items.
AskNilesh
  • 67,701
  • 16
  • 123
  • 163
Aidan Laing
  • 1,260
  • 11
  • 23
17

Przemysław's answer in Kotlin as an extension function

@SuppressLint("RestrictedApi")
fun BottomNavigationView.disableShiftMode() {
    val menuView = getChildAt(0) as BottomNavigationMenuView
    try {
        val shiftingMode = menuView::class.java.getDeclaredField("mShiftingMode")
        shiftingMode.isAccessible = true
        shiftingMode.setBoolean(menuView, false)
        shiftingMode.isAccessible = false
        for (i in 0 until menuView.childCount) {
            val item = menuView.getChildAt(i) as BottomNavigationItemView
            item.setShiftingMode(false)
            // set once again checked value, so view will be updated
            item.setChecked(item.itemData.isChecked)
        }
    } catch (e: NoSuchFieldException) {
        Log.e(TAG, "Unable to get shift mode field", e)
    } catch (e: IllegalStateException) {
        Log.e(TAG, "Unable to change value of shift mode", e)
    }
}

Usage (with Kotlin Android Extensions):

bottom_navigation_view.disableShiftMode()
ElegyD
  • 4,393
  • 3
  • 21
  • 37
12

To disable the text animation and decrease font size use this in your dimens.xml file:

<dimen name="design_bottom_navigation_text_size">10sp</dimen> 
<dimen name="design_bottom_navigation_active_text_size">10sp</dimen>
Abhishek
  • 968
  • 10
  • 16
  • One can `Navigate` -> `File...` > `design_bottom_navigation_item.xml` to see that there's no other way. – arekolek Oct 26 '17 at 14:20
11

Works for me

bottomNavigationView.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);

or

<android.support.design.widget.BottomNavigationView
    app:labelVisibilityMode="labeled" />
UgAr0FF
  • 805
  • 8
  • 18
  • mine was working just fine till target=27 but from target=28, it's broken, text no longer shown. But setLabelVisibilityMode does the trick for me, now works like a charm – joke4me Sep 19 '18 at 07:19
  • @UgArOFF the question is for disabling shift mode, not about how to enable labels! – Kishan Solanki Aug 31 '23 at 13:08
6

UPDATE

in Android sdk version 28 and above they have changed item.setShiftingMode(false) to item.setShifting(false)

Also they removed the field mShiftingMode

So usage will be

 BottomNavigationHelper.removeShiftMode(bottomNav);
 bottomNav.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);


 private static final class BottomNavigationHelper {
    @SuppressLint("RestrictedApi")
    static void removeShiftMode(BottomNavigationView view) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
        for (int i = 0; i < menuView.getChildCount(); i++) {
            BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
            //noinspection RestrictedApi
            item.setShifting(false);
            item.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);

            // set once again checked value, so view will be updated
            //noinspection RestrictedApi
            item.setChecked(item.getItemData().isChecked());
        }
    }
}
Narek Hayrapetyan
  • 1,731
  • 15
  • 27
  • you can use this code below. @SuppressLint("RestrictedApi") fun removeShiftMode(view: BottomNavigationView) { val menuView = view.getChildAt(0) as BottomNavigationMenuView menuView.labelVisibilityMode = LabelVisibilityMode.LABEL_VISIBILITY_LABELED menuView.buildMenuView() } – Deep P May 13 '19 at 23:48
5

As others have pointed out, since support library 28.0.0-alpha1 it is possible:

<android.support.design.widget.BottomNavigationView
app:labelVisibilityMode="labeled" />

or you can set it programatically.

Note: if you are upgrading from an older version of support library, do not forget to raise compile SDK version. Check versions of support libraray here: Support Library versions

However, you may still get labelVisibilityMode not found message when compile, if your app depends on older versions of the design support library. If this is the case, try to upgrade to a version of the given dependency, that depends on at least the version of 28.0.0-alpha1 of design support library. If that's not possible, define the dependency explicitly.

If you use Gradle

  1. You can check your depdendecies by running dependencies task and search for the version number of com.android.support:design.
  2. To add design support dependency explicitly in your build.gradle:

    implementation 'com.android.support:design:28.0.0'

5

For updated answer using the default. Update to latest design library

implementation "com.android.support:design:28.0.0"

and put to your BottomNavigationView xml attributes

app:itemHorizontalTranslationEnabled="false"

you can put it also as programmatically

bottomNavigationView.setItemHorizontalTranslationEnabled(false);

You can find source here BottomNavigationView

Hope this helps you.

Lester L.
  • 959
  • 1
  • 9
  • 18
  • What does this different from `app:labelVisibilityMode`? – wonsuc Mar 25 '19 at 11:38
  • @wonsuc this is about the animation of icon and text the selected item is animating. While labelVisibilityMode is for displaying whether you want to show icon with text, or just icon to be displayed when selected. – Lester L. Mar 25 '19 at 12:27
3

To your BottomNavigationView add app:labelVisibilityMode="unlabeled"

<android.support.design.widget.BottomNavigationView
        app:menu="@menu/bn_menu"
        android:layout_height="56dp"
        android:layout_width="match_parent"
        app:labelVisibilityMode="unlabeled">

</android.support.design.widget.BottomNavigationView>

which results in the following

Android Bottom Navigation View Disable Text and Shift

All Іѕ Vаиітy
  • 24,861
  • 16
  • 87
  • 111
3

It's very simple, Just add a property in BottomNaviationView

app:labelVisibilityMode="unlabeled"
Nevil Ghelani
  • 687
  • 10
  • 10
2

I had some weird behavior with BottomNavigationView. When I was selecting any item/fragment in it, the fragment pushes BottomNavigationView a bit lower, so text of BottomNavigationView goes below the screen, so only icons were visible and text goes hidden on clicking of any item.

If you are facing that weird behavior then Here is the solution. Just remove

android:fitsSystemWindows="true"

in your root layout of fragment. Just remove this and boom! BottomNavigationView will work fine, now it can be shown with text and icon. I had this in my root CoordinatorLayout of fragment.

Also don't forget to add

BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);

in your activity to disable shifting mode. Though it is not exactly related to the asked question, but still I find this helpful.

Kishan Solanki
  • 13,761
  • 4
  • 85
  • 82
2

This is a third party library I use and it has many customization options like disabling shift mode, showing only icons, setting icons size, etc. BottomNavigationViewEx

Pei
  • 11,452
  • 5
  • 41
  • 45
2

To completely remove animations:

If you also want to get rid of that annoying little top margin animation, you need more reflection code. Here's the complete solution that removes any animation:

@SuppressLint("RestrictedApi")
private static void disableShiftMode(BottomNavigationView view) {
    BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
    try {
        Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
        shiftingMode.setAccessible(true);
        shiftingMode.setBoolean(menuView, false);
        shiftingMode.setAccessible(false);
        for (int i = 0; i < menuView.getChildCount(); i++) {
            BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
            item.setShiftingMode(false);

            Field shiftAmount = item.getClass().getDeclaredField("mShiftAmount");
            shiftAmount.setAccessible(true);
            shiftAmount.setInt(item, 0);
            shiftAmount.setAccessible(false);

            item.setChecked(item.getItemData().isChecked());
        }
    } catch (NoSuchFieldException e) {
        Timber.e(e, "Unable to get fields");
    } catch (IllegalAccessException e) {
        Timber.e(e, "Unable to change values");
    }
}

And make sure to add that to your proguard configuration file:

-keepclassmembers class android.support.design.internal.BottomNavigationMenuView { 
    boolean mShiftingMode; 
}
-keepclassmembers class android.support.design.internal.BottomNavigationItemView { 
    int mShiftAmount;
}
Fred Porciúncula
  • 8,533
  • 3
  • 40
  • 57
  • Android 9 (API level 28) introduces new restrictions on the use of non-SDK interfaces and this would not work if targeting 28. https://developer.android.com/about/versions/pie/restrictions-non-sdk-interfaces – ernestkamara Oct 02 '18 at 08:07
2

update your support library to 28.0.0.

bottomNav.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
M Moersalin
  • 290
  • 3
  • 12
1

If you are using support:design:28.0.0 add this line app:labelVisibilityMode="unlabeled" to your BottomNavigationView

Omar Hassan
  • 727
  • 1
  • 11
  • 24
1

I use Android Studio 4.0.1 to develop it. The following is my result... enter image description here

About BottomNavigationViewHelper.java My code is work here

import com.google.android.material.bottomnavigation.BottomNavigationItemView;
import com.google.android.material.bottomnavigation.BottomNavigationMenuView;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.bottomnavigation.LabelVisibilityMode;
import android.annotation.SuppressLint;
import android.util.Log;
import java.lang.reflect.Field;
public class BottomNavigationViewHelper {
    @SuppressLint("RestrictedApi")
    public static void disableShiftMode(BottomNavigationView view) {
        view.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
        try {
            Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
            shiftingMode.setAccessible(true);
            shiftingMode.setBoolean(menuView, false);
            shiftingMode.setAccessible(false);
            for (int i = 0; i < menuView.getChildCount(); i++) {
                BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
                //noinspection RestrictedApi
                item.setShifting(false);
                item.setLabelVisibilityMode( LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
                // set once again checked value, so view will be updated
                //noinspection RestrictedApi
                item.setChecked(item.getItemData().isChecked());
            }
        } catch (NoSuchFieldException e) {
            Log.e("BNVHelper", "Unable to get shift mode field", e);
        } catch (IllegalAccessException e) {
            Log.e("BNVHelper", "Unable to change value of shift mode", e);
        }
    }
}

Then we can start to use BottomNavigationViewHelper class And this is my code for MainActivity.java.

BottomNavigationView navView = findViewById(R.id.nav_view); BottomNavigationViewHelper.disableShiftMode(navView);

import android.os.Bundle;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        BottomNavigationView navView = findViewById(R.id.nav_view);
        BottomNavigationViewHelper.disableShiftMode(navView);
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.navigation_settings,
                R.id.navigation_connection,
                R.id.navigation_status,
                R.id.navigation_report,
                R.id.navigation_profile
        ).build();

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
        NavigationUI.setupWithNavController(navView, navController);
        getSupportActionBar().hide();
    }
}
Milo Chen
  • 3,617
  • 4
  • 20
  • 36
  • Do you even read previously posted answers before posting new ones or just post them? This answer was already posted in this question. – Kishan Solanki Aug 31 '23 at 13:15
0

just want to add that above this method disableShiftMode add below code too. @SuppressLint("RestrictedApi")

Aleesha Kanwal
  • 187
  • 2
  • 9
0

https://android.jlelse.eu/disable-shift-label-animation-from-bottom-navigation-android-b42a25dcbffc

1

<com.google.android.material.bottomnavigation.BottomNavigationView
...
app:itemHorizontalTranslationEnabled="false"/>

2

<com.google.android.material.bottomnavigation.BottomNavigationView
...
app:labelVisibilityMode="labeled"/>

3

<resources xmlns:tools="http://schemas.android.com/tools">
<dimen name="design_bottom_navigation_active_text_size"
    tools:override="true">12sp</dimen>

k4dima
  • 6,070
  • 5
  • 41
  • 39
-1

You can use this for showing both text and icons on BottomNevigationView for 3 to 5 items and stop shifting.

 app:labelVisibilityMode="labeled"

But you will will face a problem of long text cutting on BottmNevigationView for 5 items. for that ,I found a good solutions for stop shifting of text as well as icons of BottomNevigationView. You can also stop shifting of text as well as Icons on BottomNevigationView also. Snipshots of code is given here.

1. Add this some line of code in BottomNevigationView as shown

<android.support.design.widget.BottomNavigationView
    android:id="@+id/bottom_navigation"
    android:layout_width="match_parent"
    android:layout_height="@dimen/seventy_dp"
    android:layout_semitransparent="true"
    android:background="@color/colorBottomNev"
    android:showAsAction="always|withText"
    app:itemIconTint="@drawable/bottom_navigation_colors"
    app:itemTextColor="@drawable/bottom_navigation_colors"
    app:itemTextAppearanceActive="@style/BottomNavigationViewTextStyle"
    app:itemTextAppearanceInactive="@style/BottomNavigationViewTextStyle"
    app:menu="@menu/bottom_navigation_menu"
    app:labelVisibilityMode="labeled"/>

2. Add Menu Items like as follows:-

 <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/action_catalogue"
        android:icon="@drawable/catalogue"
        android:title="@string/catalogue"
        android:enabled="true"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/action_contracts"
        android:icon="@drawable/contract"
        android:title="@string/contracts"
        android:enabled="true"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/action_prospects"
        android:icon="@drawable/prospect"
        android:title="@string/prospects"
        android:enabled="true"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/action_performance"
        android:icon="@drawable/performance"
        android:title="@string/performance"
        android:enabled="true"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/action_advance"
        android:icon="@drawable/advance"
        android:title="@string/advance"
        android:enabled="true"
        app:showAsAction="ifRoom" />

</menu>

3.Add this style in style.xml file:

 <style name="BottomNavigationViewTextStyle">
            <item name="android:fontFamily">@font/montmedium</item>
            <item name="android:textSize">10sp</item>
            <item name="android:duplicateParentState">true</item>
            <item name="android:ellipsize">end</item>
            <item name="android:maxLines">1</item>
        </style>

4)Add these in Dimen folder

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
    <dimen name="design_bottom_navigation_text_size" tools:override="true">10sp</dimen>
    <dimen name="design_bottom_navigation_active_text_size" tools:override="true">10sp</dimen>
</resources>

I got help from these link and link .You can also get get help by studying these links.This helps me a lot.Hope this also help you. Thanks....

Rahul Kushwaha
  • 5,473
  • 3
  • 26
  • 30