¿Cómo deshabilitar el modo de cambio BottomNavigationView?

146

BottomNavigationView no muestra el título del menú que está inactivo.

¿Cómo mostrar los títulos de todos los elementos del menú en bottomNavigationBar? El problema es que en mi caso solo se muestra el título del elemento en el que se hace clic.

ingrese la descripción de la imagen aquí

Natan Rubinstein
fuente
1
Posible duplicado de la nueva barra de navegación inferior
Radhey
Aquí hay una respuesta útil si desea eliminar por completo cualquier animación: stackoverflow.com/a/51052247/2352699
Fred Porciúncula

Respuestas:

330

La implementación de BottomNavigationViewtiene condición: cuando hay más de 3 elementos, utilice el modo de turno.

En este momento no puede cambiarlo a través de la API existente y la única forma de deshabilitar el modo de cambio es usar la reflexión.

Necesitarás clase auxiliar:

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);
        }
    }
}

Y luego aplique el disableShiftModemétodo en su BottomNavigationView, pero recuerde que si está inflando la vista del menú desde su código, debe ejecutarlo después de inflarlo.

Ejemplo de uso:

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

PD.

Recuerde, deberá ejecutar este método cada vez que cambie los elementos del menú en su BottomNavigationView.

ACTUALIZAR

También debe actualizar el archivo de configuración de proguard (por ejemplo, proguard-rules.pro), el código anterior usa la reflexión y no funcionará si proguard ofusca el mShiftingModecampo.

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

Gracias Muhammad Alfaifi por señalar este problema y proporcionar un fragmento .

ACTUALIZACIÓN 2

Como Jolanda Verhoef señaló que la nueva biblioteca de Soporte ( 28.0.0-alpha1) y también la nueva biblioteca de Componentes de Material ( 1.0.0-beta01) ofrece una propiedad pública que puede usarse para manipular el modo de cambio en 3 elementos de menú.

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

En la biblioteca de Componentes de material también se aplica si hay 5 elementos de menú.

ACTUALIZACIÓN 3

Como también señaló @ThomasSunderland, puede establecer esta propiedad en falso app:itemHorizontalTranslation="false"sin Enabledpostfix para deshabilitar la animación de desplazamiento.

Puede consultar la guía completa para diseñar el BottomNavigation aquí

Przemysław Piechota. kibao
fuente
10
**** Proguard :(
Muhammad Alfaifi
17
El campo se ofuscará, así que no hay forma de cambiar su valor a menos que lo excluya en su archivo de reglas de
protección
8
-keepclassmembers class android.support.design.internal.BottomNavigationMenuView {boolean mShiftingMode; }
Muhammad Alfaifi
8
A veces, realmente me pregunto por qué Google fuerza sus implementaciones de vista en los desarrolladores. Si bien hay 4 opciones en la aplicación Google+, esta simple función debería haber sido accesible a través de una función simple, si está disponible. Un problema similar ocurrió con TabLayout, que se solucionó mucho más tarde en la biblioteca de soporte. Gracias por esa solución a Original Replier y @MuhammadAlfaifi por mejorar esto.
sud007
19
La nueva biblioteca de soporte (28.0.0-alpha1) admite cambiar este comportamiento a través de la aplicación: labelVisibilityMode = "label"
Jolanda Verhoef
50

Desde la biblioteca de soporte 28.0.0-alpha1:

<android.support.design.widget.BottomNavigationView
    app:labelVisibilityMode="labeled" />
Junbin Deng
fuente
1
Estoy usando esta versión de la biblioteca de soporte, pero sigo recibiendo un error en "labelVisibilityMode" no encontrado.
Sagar Maiyad
1
Trabajando apropiadamente. No hay necesidad de reflexionar. Muchas gracias
Bhupesh
1
@Riser asegurarse de que está utilizando app:noandroid:
Carson Holzheimer
28

Para deshabilitar la animación de texto, también puede usar esto en su archivo dimens.xml:

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

Es posible que también deba agregar esto en su manifiesto:

tools:override="true"
Pafoid
fuente
no funciona. Creo que tuve que agregar esto en /values/dimens.xml?
Rohan Kandwal
10
@RohanKandwal necesita agregartools:override="true"
Boy
@ Chico Gracias, lo intentaré.
Rohan Kandwal
solo cambia el tamaño del texto.
The Dude
Solo necesito poner así en mi archivo dimens.xml:<dimen name="design_bottom_navigation_active_text_size" tools:ignore="PrivateResource">12sp</dimen>
Fernando Barbosa
22

Ahora puede usar app:labelVisibilityMode="[labeled, unlabeled, selected, auto]"en28-alpha

  • labeled mantendrá todas las etiquetas visibles.
  • unlabeled solo mostrará iconos.
  • selected solo mostrará la etiqueta del elemento seleccionado y los elementos de turno.
  • autoelegirá etiquetado o seleccionado según la cantidad de elementos que tenga. etiquetado para 1-3 artículos y seleccionado para 3+ artículos.
Aidan Laing
fuente
1
gracias Lunkie! Esta es la mejor y más fácil solución para mí
Gregriggins36
Dónde agregar esta línea de código. Intenté agregar pero hay un error que no se encuentra.
Abdulwahid
@Abdulwahid puede agregar esto en el xml de la barra de navegación inferior una vez que tenga la biblioteca de soporte 28 o superior
Aidan Laing
@Lunkie gracias ahora está claro una vez que la biblioteca de soporte 28
Abdulwahid
17

La respuesta de Przemysław en Kotlin como una función de extensión

@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)
    }
}

Uso (con extensiones de Android Kotlin):

bottom_navigation_view.disableShiftMode()
ElegyD
fuente
Trabajando para Kotlin. ¿Por qué necesitamos usar esta anotación @SuppressLint ("RestrictedApi") ¿Puedes explicar por favor?
Ranjith Kumar
11

Funciona para mi

bottomNavigationView.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);

o

<android.support.design.widget.BottomNavigationView
    app:labelVisibilityMode="labeled" />
UgAr0FF
fuente
el mío funcionaba bien hasta target = 27 pero from target = 28, está roto, el texto ya no se muestra. Pero setLabelVisibilityMode hace el truco para mí, ahora funciona como un encanto
broma4me
10

Para deshabilitar la animación de texto y disminuir el tamaño de fuente, use esto en su archivo dimens.xml:

<dimen name="design_bottom_navigation_text_size">10sp</dimen> 
<dimen name="design_bottom_navigation_active_text_size">10sp</dimen>
Abhishek
fuente
Uno puede Navigate-> File...> design_bottom_navigation_item.xmlpara ver que no hay otra manera.
arekolek
6

ACTUALIZAR

en Android SDK versión 28 y superior, han cambiado item.setShiftingMode(false)aitem.setShifting(false)

También quitaron el campo. mShiftingMode

Entonces el uso será

 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
fuente
Puedes usar este código a continuación. @SuppressLint ( "RestrictedApi") diversión removeShiftMode (Ver: BottomNavigationView) {val menuView = view.getChildAt (0) como BottomNavigationMenuView menuView.labelVisibilityMode = LabelVisibilityMode.LABEL_VISIBILITY_LABELED menuView.buildMenuView ()}
Profundo P
5

Como otros han señalado, desde la biblioteca de soporte 28.0.0-alpha1 es posible:

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

o puedes configurarlo programáticamente .

Nota: si está actualizando desde una versión anterior de la biblioteca de soporte, no olvide aumentar la versión de compilación SDK. Verifique las versiones de libraray de soporte aquí: versiones de la biblioteca de soporte

Sin embargo, aún puede recibir el mensaje labelVisibilityMode no encontrado al compilar, si su aplicación depende de versiones anteriores de la biblioteca de soporte de diseño. Si este es el caso, intente actualizar a una versión de la dependencia dada, que depende de al menos la versión 28.0.0-alpha1 de la biblioteca de soporte de diseño. Si eso no es posible, defina la dependencia explícitamente.

Si usas Gradle

  1. Puede verificar sus dependencias ejecutando la tarea de dependencias y buscando el número de versión de com.android.support:design .
  2. Para agregar una dependencia de soporte de diseño explícitamente en su build.gradle :

    implementación 'com.android.support:design:28.0.0'

Richárd Bogdán
fuente
4

Para respuesta actualizada utilizando el valor predeterminado. Actualización a la última biblioteca de diseño

implementación "com.android.support:design:28.0.0"

y poner a sus atributos xml BottomNavigationView

app:itemHorizontalTranslationEnabled="false"

puedes ponerlo también como programáticamente

bottomNavigationView.setItemHorizontalTranslationEnabled(false);

Puede encontrar la fuente aquí BottomNavigationView

Espero que esto te ayude.

Lester L.
fuente
¿De qué difiere esto app:labelVisibilityMode?
wonsuc
@wonsuc se trata de la animación del icono y el texto que está animando el elemento seleccionado. Mientras labelVisibilityMode es para mostrar si desea mostrar el icono con texto, o simplemente el icono que se mostrará cuando se seleccione.
Lester L.
3

A su BottomNavigationViewcomplementoapp: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>

lo que resulta en lo siguiente

Vista de navegación inferior de Android Desactivar texto y Shift

Todo es variado
fuente
3

Es muy simple, solo agregue una propiedad en BottomNaviationView

app:labelVisibilityMode="unlabeled"
Nevil Ghelani
fuente
2

Tuve un comportamiento extraño con BottomNavigationView. Cuando estaba seleccionando cualquier elemento / fragmento en él, el fragmento empuja BottomNavigationView un poco más abajo, por lo que el texto de BottomNavigationView va debajo de la pantalla, por lo que solo los iconos estaban visibles y el texto se oculta al hacer clic en cualquier elemento.

Si se enfrenta a ese comportamiento extraño, entonces esta es la solución. Solo eliminar

android:fitsSystemWindows="true"

en su diseño raíz de fragmento. Solo elimina esto y ¡boom! BottomNavigationView funcionará bien, ahora se puede mostrar con texto e ícono. Tenía esto en mi raíz CoordinatorLayout of fragment.

Tampoco olvides agregar

BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);

en su actividad para desactivar el modo de cambio. Aunque no está exactamente relacionado con la pregunta formulada, aún así encuentro esto útil.

Kishan Solanki
fuente
1
@ abbath0767 ¿has visto vincular esto? Puede ser útil para ti.
Kishan Solanki
Pensé que ya había intentado todo, muchas gracias, no esperaba encontrar directamente la respuesta que estaba buscando.
BekaBot
1
Placer @BekaBot
Kishan Solanki
2

Esta es una biblioteca de terceros que uso y tiene muchas opciones de personalización, como deshabilitar el modo de cambio, mostrar solo íconos, configurar el tamaño de los íconos, etc. BottomNavigationViewEx

Pei
fuente
2

Para eliminar completamente las animaciones:

Si también desea deshacerse de esa pequeña y molesta animación de margen superior, necesita más código de reflexión. Aquí está la solución completa que elimina cualquier animación:

@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");
    }
}

Y asegúrese de agregar eso a su archivo de configuración de protección:

-keepclassmembers class android.support.design.internal.BottomNavigationMenuView { 
    boolean mShiftingMode; 
}
-keepclassmembers class android.support.design.internal.BottomNavigationItemView { 
    int mShiftAmount;
}
Fred Porciúncula
fuente
Android 9 (nivel de API 28) introduce nuevas restricciones en el uso de interfaces que no son SDK y esto no funcionaría si
apuntara
2

Actualice su biblioteca de soporte a 28.0.0.

bottomNav.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
M Moersalin
fuente
1

Si usa support: design: 28.0.0 agregue esta aplicación de línea: labelVisibilityMode = "sin etiqueta" a su BottomNavigationView

Omar Hassan
fuente
0

solo quiero agregar eso por encima de este método disableShiftMode agregar el código a continuación también. @SuppressLint ("RestrictedApi")

Aleesha Kanwal
fuente
-1

Puede usar esto para mostrar texto e íconos en BottomNevigationView para 3 a 5 elementos y detener el cambio.

 app:labelVisibilityMode="labeled"

Pero enfrentará un problema de corte de texto largo en BottmNevigationView para 5 elementos. para eso, encontré una buena solución para detener el desplazamiento de texto, así como los íconos de BottomNevigationView. También puede detener el desplazamiento de texto, así como los iconos en BottomNevigationView también. Aquí se proporcionan instantáneas de código.

1. Agregue esto alguna línea de código en BottomNevigationView como se muestra

<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. Agregue elementos de menú de la siguiente manera: -

 <?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.Agregue este estilo en el archivo style.xml:

 <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) Agregar estos en la carpeta Dimen

<?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>

Obtuve ayuda de estos enlaces y enlaces . También puedes obtener ayuda estudiando estos enlaces. Esto me ayuda mucho. Espero que esto también te ayude. Gracias....

Rahul Kushwaha
fuente