BottomNavigationView - 如何取消选中所有MenuItem并保持标题显示?

时间:2016-12-29 02:18:17

标签: android title menuitem bottomnavigationview

由于我喜欢BottomNavigationView的设计,我决定用它为我的应用程序实现一个新的菜单,而不是仅使用简单的按钮。

我以this帖子作为指导。

根据BottomNavigationView的{​​{3}},其目的是

  

在应用的顶级视图之间提供快速导航。它是   主要设计用于移动设备。

就我而言,我只希望每个MenuItem启动一项活动,但默认情况下总会选择一个MenuItem

documentation

我尝试将颜色设置为白色:

app:itemIconTint="@color/white"
app:itemTextColor="@color/white"

尽管如此,明显选择MenuItem与其他人(标题大小更大)不同,这仍然困扰着我:

enter image description here

我想出了一个隐藏的MenuItem来选择:

<item
android:id="@+id/uncheckedItem"
android:title="" />

并查看其GONE

 bottomNavigationView.getMenu().findItem(R.id.uncheckedItem).setChecked(true);
 bottomNavigationView.findViewById(R.id.uncheckedItem).setVisibility(View.GONE);

这会取消选中所有MenuItem,但默认情况下BottomNavigationView会隐藏标题,因为它有超过3个要显示的MenuItem,即使第四个MenuItem已合并到GONE:< / p>

enter image description here

所以我的问题仍然存在,是否存在/黑客取消选择所有MenuItem并保持其标题显示?

10 个答案:

答案 0 :(得分:14)

mNavigationBottom.getMenu().setGroupCheckable(0, false, true);

答案 1 :(得分:5)

谢谢你的想法。我在我的lib中实现它。 通过反思,我有更好的方法。所以它不会显示空间。

如果您有兴趣。点击此处:https://github.com/ittianyu/BottomNavigationViewEx

private void initBottomViewAndLoadFragments(final BottomNavigationViewEx bnve) {
    bnve.enableAnimation(false);
    bnve.enableShiftingMode(false);
    bnve.enableItemShiftingMode(false);

    // use the unchecked color for first item
    bnve.setIconTintList(0, getResources().getColorStateList(R.color.bnv_unchecked_black));
    bnve.setTextTintList(0, getResources().getColorStateList(R.color.bnv_unchecked_black));

    bnve.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {

        private boolean firstClick = true;
        private int lastItemId = -1;

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            // restore the color when click
            if (firstClick) {
                firstClick = false;
                bnve.setIconTintList(0, getResources().getColorStateList(R.color.selector_bnv));
                bnve.setTextTintList(0, getResources().getColorStateList(R.color.selector_bnv));
            }

            if (firstClick || lastItemId == -1 || lastItemId != item.getItemId()) {
                lastItemId = item.getItemId();
            } else {
                return false;
            }

            // do stuff
            return fillContent(item.getItemId());
        }
    });
}

- res / color / selector_bnv.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/bnv_checked_white" android:state_checked="true" />
    <item android:color="@color/bnv_unchecked_black" />
</selector>

- res / values / colors.xml

<color name="bnv_checked_white">@android:color/white</color>
<color name="bnv_unchecked_black">@android:color/black</color>

答案 2 :(得分:2)

我找到了自己的解决方案,将我的进度与this帖子合并。

<强>步骤:

  1. 更新proguard-rules.pro并同步构建
  2. 创建助手以禁用BottomNavigationView班次模式
  3. 创建要在Menu.xml上隐藏的项目
  4. Inflate BottomNavigationView
  5. 将项目设置为隐藏为已检查GONE
  6. 使用助手禁用转移模式
  7. <强>输出:

    enter image description here

    工作代码:

    proguard-rules.pro:

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

    BottomNavigationShiftHelper.java:

    public class BottomNavigationShiftHelper {
    
        private final static String TAG = "DEBUG_BOTTOM_NAV_UTIL";
    
        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);
                    item.setShiftingMode(false);
                    // set once again checked value, so view will be updated
                    item.setChecked(item.getItemData().isChecked());
                }
            } catch (NoSuchFieldException e) {
                Log.d(TAG, "Unable to get shift mode field");
            } catch (IllegalAccessException e) {
                Log.d(TAG, "Unable to change value of shift mode");
            }
        }
    }
    

    活动Sample.java:

     private void loadNavigationBar() {
            BottomNavigationView bottomNavigationView = (BottomNavigationView)
                    findViewById(R.id.navigation_bar);
    
            bottomNavigationView.getMenu().findItem(R.id.uncheckedItem).setChecked(true);
            bottomNavigationView.findViewById(R.id.uncheckedItem).setVisibility(View.GONE);
    
            BottomNavigationViewUtils.disableShiftMode(bottomNavigationView);
    
            bottomNavigationView.setOnNavigationItemSelectedListener(
                    new BottomNavigationView.OnNavigationItemSelectedListener() {
                        @Override
                        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                            switch (item.getItemId()) {
                                case R.id.newList:
                                    //Do The Math
                                    break;
                                case R.id.loadList:
                                    //Do The Math
                                    break;
                                case R.id.settings:
                                    //Do The Math
                                    break;
                            }
                            return false;
                        }
                    });
        }
    

    BottomNavigationMenu.xml:

    <?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/newList"
            android:enabled="true"
            android:icon="@drawable/new_list"
            android:title="@string/common.button.list.new"
            app:showAsAction="withText" />
        <item
            android:id="@+id/loadList"
            android:enabled="true"
            android:icon="@drawable/load"
            android:title="@string/common.button.list.load"
            app:showAsAction="withText" />
        <item
            android:id="@+id/settings"
            android:enabled="true"
            android:icon="@drawable/settings"
            android:title="@string/common.label.settings"
            app:showAsAction="withText" />
        <item
            android:id="@+id/uncheckedItem"
            android:title="" />
    </menu>
    

    BottomNavigationComponent(在Activity.xml中):

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation_bar"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        app:itemIconTint="@color/white"
        app:itemTextColor="@color/white"
        android:background="@drawable/BottomNavigationMenu.xml"
        app:menu="@menu/supercart_bottom_navigation" />
    

答案 3 :(得分:2)

您的解决方案似乎改变了项目之间的空间

有我的解决方案:

&#34;只需将点击的颜色设置为未点击的颜色即可。&#34;

例如:

private void changeMenuItemCheckedStateColor(BottomNavigationView bottomNavigationView, String checkedColorHex, String uncheckedColorHex) {
    int checkedColor = Color.parseColor(checkedColorHex);
    int uncheckedColor = Color.parseColor(uncheckedColorHex);

    int[][] states = new int[][] {
            new int[] {-android.R.attr.state_checked}, // unchecked
            new int[] {android.R.attr.state_checked}, // checked

    };

    int[] colors = new int[] {
            uncheckedColor,
            checkedColor
    };

    ColorStateList colorStateList = new ColorStateList(states, colors);

    bottomNavigationView.setItemTextColor(colorStateList);
    bottomNavigationView.setItemIconTintList(colorStateList);

}

如果您要取消选中所有项目,可以

changeMenuItemCheckedStateColor(mBottomNavigationView, "#999999", "#999999");

如果要恢复颜色设置,可以

changeMenuItemCheckedStateColor(mBottomNavigationView, "FF743A", "999999");

答案 4 :(得分:2)

要取消选择所有我已创建此扩展程序的项目,

fun BottomNavigationView.uncheckAllItems() {
    menu.setGroupCheckable(0, true, false)
    for (i in 0 until menu.size()) {
        menu.getItem(i).isChecked = false
    }
    menu.setGroupCheckable(0, true, true)
}

menu.setGroupCheckable(0,true,false)使之成为可能。 第三个参数使菜单不是唯一的,然后在循环中更改检查状态。 最后,将菜单再次设置为独占。

Here the doc

答案 5 :(得分:1)

尝试一下,它对我有用

 <item
    android:id="@+id/uncheckedItem"
    android:visible="false"
    android:title="" />

并设置

bottomNavigationView.getMenu().findItem(R.id.uncheckedItem).setChecked(true);

enter image description here

您将所有菜单项视图设为未选中;因为选择是针对uncheckedItem的,所以它是不可见的

希望它对您有所帮助。

答案 6 :(得分:0)

这与接受的答案相同,只是我更改了下面标记的两行代码。循环遍历BottomNavigationItemViews时,我总是将checked设置为false,并且我也将checkable设置为false。这可以防止菜单项更改大小。你仍然需要这个proguard规则:

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

更新的代码:

    static void removeShiftMode(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);
                item.setChecked(false); // <--- This line changed
                item.setCheckable(false);  // <-- This line was added
            }
        }
        catch (NoSuchFieldException e)
        {
            Log.e("ERROR NO SUCH FIELD", "Unable to get shift mode field");
        }
        catch (IllegalAccessException e)
        {
            Log.e("ERROR ILLEGAL ALG", "Unable to change value of shift mode");
        }

   }

答案 7 :(得分:0)

最佳答案mNavigationBottom.getMenu().setGroupCheckable(0, false, true)对我不起作用。它仍然显示第一项被选中。

对我来说,起作用的是拥有一个隐形物品并选择它,就像您在问题中所做的一样。

app:labelVisibilityMode="labeled"添加到您的BottomNavigationView中,以便所有项目及其标题保持可见。

答案 8 :(得分:0)

在接受的答案中有一个例外,我们设置了我们无法实现该代码的最大项目数。因此,我得到的代码比接受的代码更简单,并且也可以处理最大项目数。

我从这里引荐Custom TextSize of BottomNavigationView support android

在您的dimen.xml中,您可以放置​​:

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

这样做将覆盖BottomNavigationView内部类使用的dimen的默认值。所以要小心。

在初始化底部导航视图的 onCreate 方法中设置此代码

mNavigationBottom.getMenu().setGroupCheckable(0, false, true);

最后,像这样设置您的底部导航栏:

 <com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/nav_view"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:layout_gravity="bottom"
    android:background="?android:attr/windowBackground"
    android:fitsSystemWindows="true"
    app:labelVisibilityMode="labeled"
    app:layout_anchorGravity="fill"
    app:menu="@menu/bottom_nav_menu" />

在这种情况下,将您的 app:labelVisibilityMode 设置为已标记

答案 9 :(得分:0)

    if(isDarkMode(context)) {
        mBotNavView.setItemIconTintList(ColorStateList.valueOf(Color.parseColor("#FFFFFF")));
    } else {
        mBotNavView.setItemIconTintList(ColorStateList.valueOf(Color.parseColor("#000000")));
    }

    public boolean isDarkMode(Context context) {
        int nightModeFlags = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
        return darkMode = (nightModeFlags == Configuration.UI_MODE_NIGHT_YES);
    }