Как отключить режим сдвига BottomNavigationView?

BottomNavigationView не показывает заголовок меню, которые неактивны.

Как показать названия всех элементов меню в bottomNavigationBar? Проблема в том, что в моем случае отображается только название элемента, по которому щелкают.

введите описание изображения здесь

16 ответов

Решение

Реализация BottomNavigationView имеет условие: при наличии более 3-х предметов используйте режим смены.

В данный момент вы не можете изменить его с помощью существующего API, и единственный способ отключить режим сдвига - это использовать отражение.

Вам понадобится вспомогательный класс:

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

А затем применить disableShiftMode метод на вашем BottomNavigationView, но помните, если вы надуваете представление меню из своего кода, вы должны выполнить его после надувания.

Пример использования:

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

PS.

Помните, что вам нужно выполнять этот метод каждый раз, когда вы меняете пункты меню в вашем BottomNavigationView,

ОБНОВИТЬ

Вам также необходимо обновить конфигурационный файл proguard (например, proguard-rules.pro), приведенный выше код использует отражение и не будет работать, если proguard запутывает mShiftingMode поле.

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

Спасибо Мухаммеду Альфаифи за указание на эту проблему и предоставление фрагмента.

ОБНОВЛЕНИЕ 2

Как отметила Jolanda Verhoef, новая библиотека поддержки (28.0.1-alpha1), а также новая библиотека компонентов материалов (1.0.0-beta01) предлагает публичное свойство, которое можно использовать для управления режимом смещения над 3 пунктами меню.

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

В библиотеке компонентов материалов это также применимо, если есть 5 пунктов меню.

Начиная с библиотеки поддержки 28.0.0-alpha1:

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

Чтобы отключить текстовую анимацию, вы также можете использовать это в вашем файле измерения.xml:

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

Теперь вы можете использовать app:labelVisibilityMode="[labeled, unlabeled, selected, auto]" в 28-alpha

  • labeled будет держать все метки видимыми
  • unlabeledбудут показывать только иконки.
  • selected будет отображаться только метка для выбранного элемента и сдвиг элементов.
  • auto выберет маркированные или выбранные в зависимости от количества предметов, которые у вас есть. помечены для 1-3 предметов и выбраны для 3+ предметов.

Ответ Пшемыслава на языке котлина как функция расширения

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

Использование (с расширениями Android Kotlin):

bottom_navigation_view.disableShiftMode()

Чтобы отключить текстовую анимацию и уменьшить размер шрифта, используйте это в вашем файле измерения.xml:

<dimen name="design_bottom_navigation_text_size">10sp</dimen> 
<dimen name="design_bottom_navigation_active_text_size">10sp</dimen>

Работает для меня

bottomNavigationView.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);

или же

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

ОБНОВИТЬ

в Android SDK версии 28 и выше они изменились item.setShiftingMode(false) в item.setShifting(false)

Также они убрали поле mShiftingMode

Так что использование будет

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

Как уже отмечали другие, начиная с поддержки библиотеки 28.0.0-alpha1 возможно:

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

или вы можете установить его программно.

Примечание: если вы обновляете старую версию библиотеки поддержки, не забудьте поднять версию SDK для компиляции. Проверьте версии библиотеки поддержки здесь: Поддержка библиотеки версий

Тем не менее, вы все равно можете получить сообщение labelVisibilityMode not found при компиляции, если ваше приложение зависит от более старых версий библиотеки поддержки проектирования. Если это так, попробуйте обновить до версии с данной зависимостью, которая зависит по крайней мере от версии 28.0.0-alpha1 библиотеки поддержки проектирования. Если это невозможно, определите зависимость явно.

Если вы используете Gradle

  1. Вы можете проверить свои зависимости, запустив задачу зависимостей и найти номер версии com.android.support:design.
  2. Чтобы явно добавить поддержку поддержки дизайна в ваш build.gradle:

    реализация 'com.android.support:design:28.0.0'

Для обновленного ответа используем значение по умолчанию. Обновление до последней библиотеки дизайна

реализация "com.android.support:design:28.0.0"

и поместите в ваши атрибуты BottomNavigationView xml

app:itemHorizontalTranslationEnabled="false"

Вы можете поставить это также программно

bottomNavigationView.setItemHorizontalTranslationEnabled(false);

Вы можете найти источник здесь BottomNavigationView

Надеюсь, это поможет вам.

Это очень просто, просто добавьте свойство в BottomNaviationView

app:labelVisibilityMode="unlabeled"

На ваш BottomNavigationView добавлять 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>

что приводит к следующему

https://stackru.com/images/61d496da629a32c8c5e9d90d41895ce f2490969d.jpg

У меня было странное поведение с BottomNavigationView. Когда я выбирал какой-либо элемент / фрагмент в нем, фрагмент толкает BottomNavigationView чуть ниже, поэтому текст BottomNavigationView идет ниже экрана, поэтому видны только значки, а текст скрывается при нажатии любого элемента.

Если вы столкнулись с таким странным поведением, то вот решение. Просто удали

android:fitsSystemWindows="true"

в вашем корневом макете фрагмента. Просто уберите это и бум! BottomNavigationView будет работать нормально, теперь он может быть показан с текстом и значком. У меня было это в моем корне CoordinatorLayout фрагмента.

Также не забудьте добавить

BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);

в вашей активности, чтобы отключить режим переключения. Хотя это не совсем связано с заданным вопросом, но все же я считаю это полезным.

Обновите вашу библиотеку поддержки до 28.0.0.

bottomNav.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);

Это сторонняя библиотека, которую я использую, и она имеет много опций настройки, таких как отключение режима сдвига, отображение только значков, настройка размера значков и т. Д. https://git hub.com/ittianyu/BottomNavigationViewEx

Чтобы полностью удалить анимацию:

Если вы также хотите избавиться от этой раздражающей маленькой анимации верхнего поля, вам нужно больше кода отражения. Вот полное решение, которое удаляет любую анимацию:

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

И убедитесь, что добавили это в свой конфигурационный файл proguard:

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

Если вы используете support:design:28.0.0 добавьте эту строку app:labelVisibilityMode="unlabeled" в ваш BottomNavigationView

Я использую Android Studio 4.0.1 для его разработки. Вот мой результат...

О BottomNavigationViewHelper.java Мой код работает здесь

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

Затем мы можем начать использовать класс BottomNavigationViewHelper. Это мой код для 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();
    }
}

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>

Просто хочу добавить, что выше этого метода disableShiftMode добавить ниже код тоже. @SuppressLint("RestrictedApi")

Вы можете использовать это для отображения текста и значков в BottomNevigationView от 3 до 5 элементов и остановки сдвига.

 app:labelVisibilityMode="labeled"

Но вы столкнетесь с проблемой обрезки длинного текста в BottmNevigationView для 5 элементов. для этого я нашел хорошее решение для остановки смещения текста, а также иконки BottomNevigationView. Вы также можете остановить смещение текста и значков в BottomNevigationView. Фрагменты кода приведены здесь.

1. Добавьте эту строку кода в BottomNevigationView, как показано

<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. Добавьте пункты меню следующим образом: -

 <?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. Добавьте этот стиль в файл 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) Добавьте их в папку 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>

Я получил помощь по этой ссылке и ссылке. Вы также можете получить помощь, изучив эти ссылки. Это мне очень помогает. Надеюсь, это также поможет вам. Спасибо....

Другие вопросы по тегам