如何禁用 BottomNavigationView 移位模式?

Posted

技术标签:

【中文标题】如何禁用 BottomNavigationView 移位模式?【英文标题】:How to disable BottomNavigationView shift mode? 【发布时间】:2017-03-03 17:47:32 【问题描述】:

BottomNavigationView 不显示处于非活动状态的菜单标题。

如何在底部导航栏中显示所有菜单元素的标题? 问题是在我的例子中只显示了被点击元素的标题。

【问题讨论】:

android new Bottom Navigation bar的可能重复 如果您想完全删除任何动画,这是一个有用的答案:***.com/a/51052247/2352699 【参考方案1】:

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

然后在 BottomNavigationView 上应用 disableShiftMode 方法,但请记住,如果您从代码中扩展菜单视图,则必须在扩展后执行它。

示例用法:

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; 

感谢 Muhammad Alfaifi 指出 this issue 和 providing snippet。

更新 2

正如 Jolanda Verhoef 指出的新支持库 (28.0.0-alpha1) 以及新的 Material Components library (1.0.0-beta01) 提供了一个公共属性,可用于在 3 个菜单项上操作切换模式。

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

在材料组件库中,如果有 5 个菜单项,它也适用。

更新 3

正如@ThomasSunderland 还指出的那样,您可以将此属性设置为 false app:itemHorizontalTranslation="false" 而无需 Enabled 后缀来禁用移动动画。

您可以查看底部导航样式的完整指南here

【讨论】:

**** Proguard :( 该字段将被混淆,因此除非您在 proguard-rules 文件中排除它,否则无法更改其值 -keepclassmembers class android.support.design.internal.BottomNavigationMenuView boolean mShiftingMode; 有时候,我真的很想知道为什么 Google 会强制开发人员使用它的视图实现。虽然 Google+ 应用程序本身有 4 个选项,但这个简单的功能应该可以通过一个简单的功能(如果可用)来访问! TabLayout 也存在类似问题,该问题后来在支持库中得到修复。感谢 Original Replier 和 @MuhammadAlfaifi 改进此问题的解决方法。 新的支持库 (28.0.0-alpha1) 支持通过 app:labelVisibilityMode="labeled" 改变这种行为【参考方案2】:

由于支持库28.0.0-alpha1:

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

【讨论】:

我正在使用此支持库版本,但在“labelVisibilityMode”未找到时仍然出现错误。 正常工作。没有必要去反思。非常感谢 @Riser 确保您使用的是app: 而不是android:【参考方案3】:

要禁用文本动画,您也可以在 dimen.xml 文件中使用它:

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

您可能还需要在清单中添加此内容:

tools:override="true"

【讨论】:

不工作。我相信我必须将其添加到 /values/dimens.xml 中? @RohanKandwal 需要加tools:override="true" @Boy 谢谢,会试试的。 只改变文字大小。 我只需要在我的dimens.xml文件中这样写:&lt;dimen name="design_bottom_navigation_active_text_size" tools:ignore="PrivateResource"&gt;12sp&lt;/dimen&gt;【参考方案4】:

您现在可以在28-alpha 中使用app:labelVisibilityMode="[labeled, unlabeled, selected, auto]"

labeled 将保持所有标签可见。 unlabeled 将只显示图标。 selected 只会显示选中项和班次项的标签。 auto 将根据您拥有的项目数量选择已标记或已选择。标记为 1-3 项,选择 3 项以上。

【讨论】:

感谢 Lunkie!这对我来说是最好和最简单的解决方案 在哪里添加这行代码。我尝试添加但没有发现错误。 @Abdulwahid 支持库 28 或更高版本后,您可以将其添加到底部导航栏的 xml 中 @Lunkie 感谢现在很清楚一旦支持库 28【参考方案5】:

Przemysław 在 Kotlin 中作为扩展函数的回答

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

用法(使用 Kotlin Android 扩展):

bottom_navigation_view.disableShiftMode()

【讨论】:

为 kotlin 工作。为什么我们需要使用这个注解 @SuppressLint("RestrictedApi") 你能解释一下吗?【参考方案6】:

要禁用文本动画并减小字体大小,请在您的 dimens.xml 文件中使用:

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

【讨论】:

可以Navigate -> File... > design_bottom_navigation_item.xml 看看没有别的办法。【参考方案7】:

为我工作

bottomNavigationView.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);

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

【讨论】:

我的工作正常,直到 target=27,但从 target=28 开始,它坏了,不再显示文本。但是 setLabelVisibilityMode 对我有用,现在就像一个魅力【参考方案8】:

更新

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

【讨论】:

您可以在下面使用此代码。 @SuppressLint("RestrictedApi") fun removeShiftMode(view: BottomNavigationView) val menuView = view.getChildAt(0) as BottomNavigationMenuView menuView.labelVisibilityMode = LabelVisibilityMode.LABEL_VISIBILITY_LABELED menuView.buildMenuView() 【参考方案9】:

正如其他人指出的那样,由于支持库 28.0.0-alpha1,因此有可能:

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

或者你可以设置它programatically。

注意:如果您是从旧版本的支持库升级,请不要忘记提高编译 SDK 版本。 在此处检查支持库的版本:Support Library versions

但是,如果您的应用依赖于旧版本的设计支持库,则在编译时您可能仍会收到 labelVisibilityMode not found 消息。如果是这种情况,请尝试升级到给定依赖项的版本,该版本至少取决于设计支持库的 28.0.0-alpha1 版本。如果这不可能,请显式定义依赖项。

如果你使用 Gradle

    您可以通过以下方式检查您的依赖项 运行dependencies任务并搜索com.android.support:design的版本号。

    要在 build.gradle 中明确添加设计支持依赖项:

    实现'com.android.support:design:28.0.0'

【讨论】:

【参考方案10】:

对于使用默认值的更新答案。更新到最新的设计库

实现“com.android.support:design:28.0.0”

并放入您的 BottomNavigationView xml 属性

app:itemHorizontalTranslationEnabled="false"

你也可以把它写成编程方式

bottomNavigationView.setItemHorizontalTranslationEnabled(false);

你可以在这里找到源代码BottomNavigationView

希望对你有所帮助。

【讨论】:

这和app:labelVisibilityMode有什么不同? @wonsuc 这是关于所选项目正在动画的图标和文本的动画。而 labelVisibilityMode 用于显示您是要显示带有文本的图标,还是仅在选择时显示图标。【参考方案11】:

给你的BottomNavigationView添加app:labelVisibilityMode="unlabeled"

<android.support.design.widget.BottomNavigationView
        app:menu="@menu/bn_menu"
        android:layout_
        android:layout_
        app:labelVisibilityMode="unlabeled">

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

结果如下

【讨论】:

【参考方案12】:

很简单,在BottomNaviationView中添加一个属性

app:labelVisibilityMode="unlabeled"

【讨论】:

【参考方案13】:

我对 BottomNavigationView 有一些奇怪的行为。当我选择其中的任何项目/片段时,片段将 BottomNavigationView 推低一点,因此 BottomNavigationView 的文本位于屏幕下方,因此只有图标可见,并且在单击任何项​​目时文本会隐藏。

如果您遇到这种奇怪的行为,那么这里就是解决方案。 只需删除

android:fitsSystemWindows="true"

在您的片段的根布局中。只需删除它并繁荣! BottomNavigationView 可以正常工作,现在可以用文本和图标显示。 我在 Fragment 的根 CoordinatorLayout 中有这个。

别忘了添加

BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);

在您的活动中禁用换档模式。 虽然它与所提出的问题并不完全相关,但我仍然觉得这很有帮助。

【讨论】:

@abbath0767 你见过link这个吗?可能对你有帮助。 我以为我已经尝试了一切,非常感谢,没想到直接找到了我正在寻找的答案。 快乐@BekaBot【参考方案14】:

这是我使用的第三方库,它有许多自定义选项,例如禁用 shift 模式、仅显示图标、设置图标大小等。 BottomNavigationViewEx

【讨论】:

【参考方案15】:

彻底删除动画:

如果您还想摆脱那个烦人的小顶部边距动画,则需要更多反射代码。这是删除任何动画的完整解决方案:

@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;

【讨论】:

Android 9(API 级别 28)对非 SDK 接口的使用引入了新限制,如果目标为 28,这将不起作用。developer.android.com/about/versions/pie/…【参考方案16】:

将您的支持库更新到 28.0.0。

bottomNav.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);

【讨论】:

【参考方案17】:

如果您使用的是 support:design:28.0.0,请将此行 app:labelVisibilityMode="unlabeled" 添加到您的 BottomNavigationView

【讨论】:

【参考方案18】:

我使用 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();
    

【讨论】:

【参考方案19】:

只想在此方法上方添加 disableShiftMode 并在下方添加代码。 @SuppressLint("RestrictedApi")

【讨论】:

【参考方案20】:

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>

【讨论】:

【参考方案21】:

您可以使用它在 BottomNevigationView 上显示 3 到 5 个项目的文本和图标并停止移动。

 app:labelVisibilityMode="labeled"

但是你会在BottmNevigationView上遇到5个item的长文本切割问题。为此,我找到了一个很好的解决方案来停止移动文本以及 BottomNevigationView 的图标。您还可以停止移动文本以及 BottomNevigationView 上的图标。这里给出了代码的截图。

1.如图所示在BottomNevigationView中添加这行代码

<android.support.design.widget.BottomNavigationView
    android:id="@+id/bottom_navigation"
    android:layout_
    android:layout_
    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>

我从这些link 和link 获得了帮助。您也可以通过研究这些链接获得帮助。这对我有很大帮助。希望这对您也有帮助。谢谢....

【讨论】:

以上是关于如何禁用 BottomNavigationView 移位模式?的主要内容,如果未能解决你的问题,请参考以下文章

BottomNavigationView - 如何获取选定的菜单项?

如何使用 material.BottomNavigationView 设置 Jetpack 导航

如何在 BottomNavigationView 的片段上打开搜索界面?

如何在Android的BottomNavigationView中设置填充项

如何将 BottomNavigationView 与 NavigationView 一起对齐到 Activity 的底部?

Android关于BottomNavigationView效果实现指南