BottomNavigationView - 如何取消选中所有 MenuItems 并保持标题显示?
BottomNavigationView - How to uncheck all MenuItems and keep Titles being displayed?
因为我喜欢 BottomNavigationView
的设计,所以我决定用它为我的应用程序实现一个新菜单,而不仅仅是使用简单的按钮。
我以 post 作为指导。
根据BottomNavigationView
的documentation,其目的是
provide quick navigation between top-level views of an app. It is
primarily designed for use on mobile.
在我的例子中,我只希望每个 MenuItem
启动一个 activity,但默认情况下总是有一个 MenuItem
selected:
我尝试将颜色设置为白色:
app:itemIconTint="@color/white"
app:itemTextColor="@color/white"
仍然,明显地 selected MenuItem
与其他人不同(标题大小更大),这仍然困扰着我:
我想到了放置一个隐藏的 MenuItem
到 select 的想法,例如:
<item
android:id="@+id/uncheckedItem"
android:title="" />
并使其视图 GONE
:
bottomNavigationView.getMenu().findItem(R.id.uncheckedItem).setChecked(true);
bottomNavigationView.findViewById(R.id.uncheckedItem).setVisibility(View.GONE);
这会取消选中所有菜单项,但默认情况下 BottomNavigationView
会隐藏标题,因为它要显示的菜单项超过 3 个,即使第四个 MenuItem
设置为 GONE
:
所以我的问题仍然存在,是否可以 away/hack 取消 select 所有菜单项并保持其标题显示?
我找到了自己的解决方案,将我的进度与 post 合并。
步骤:
- 更新 proguard-rules.pro 并同步构建
- 创建助手以禁用 BottomNavigationView 切换模式
- 创建要隐藏的项目 Menu.xml
- 膨胀 BottomNavigationView
- 将项目设置为隐藏为已检查已消失
- 使用助手禁用移动模式
输出:
工作代码:
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");
}
}
}
Activity 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;
}
});
}
底部导航Menu.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" />
您的解决方案似乎改变了项目之间的 space
有我的解决方案:
"Just set color of clicked same as color of un-clicked."
例如:
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");
谢谢你的想法。我已经在我的库中实现了它。
我有更好的方法通过反射来做到这一点。所以它不会显示 space.
如果你有兴趣。点击此处: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>
除了我更改了下面标记的两行代码外,这与接受的答案相同。当循环浏览 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");
}
}
mNavigationBottom.getMenu().setGroupCheckable(0, false, true);
要取消选择我创建此扩展程序的所有项目:
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) 使之成为可能。
第三个参数使菜单不排他,然后在循环中更改选中状态。
再次将菜单设置为独占。
最佳答案 mNavigationBottom.getMenu().setGroupCheckable(0, false, true)
对我不起作用。它仍然显示第一项是 selected。
对我有用的是有一个看不见的项目,select,就像你在问题中所做的那样。
将 app:labelVisibilityMode="labeled"
添加到您的 BottomNavigationView
以便所有项目及其标题都保持在视图中。
接受的答案中有一个例外,我们设置了我们无法实现的最大项目code.So我得到的代码比接受的代码更简单,它也适用于最大项目。
我从这里引用 BottomNavigationView 支持的自定义 TextSize 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 的内部 类 使用的默认维度值。所以要小心。
在初始化底部导航视图的 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 设置为 labeled
试试这个,对我有用
<item
android:id="@+id/uncheckedItem"
android:visible="false"
android:title="" />
并设置
bottomNavigationView.getMenu().findItem(R.id.uncheckedItem).setChecked(true);
您将所有菜单项视图显示为未选中;因为选择的 uncheckedItem
是不可见的
希望对您有所帮助。
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);
}
因为我喜欢 BottomNavigationView
的设计,所以我决定用它为我的应用程序实现一个新菜单,而不仅仅是使用简单的按钮。
我以
根据BottomNavigationView
的documentation,其目的是
provide quick navigation between top-level views of an app. It is primarily designed for use on mobile.
在我的例子中,我只希望每个 MenuItem
启动一个 activity,但默认情况下总是有一个 MenuItem
selected:
我尝试将颜色设置为白色:
app:itemIconTint="@color/white"
app:itemTextColor="@color/white"
仍然,明显地 selected MenuItem
与其他人不同(标题大小更大),这仍然困扰着我:
我想到了放置一个隐藏的 MenuItem
到 select 的想法,例如:
<item
android:id="@+id/uncheckedItem"
android:title="" />
并使其视图 GONE
:
bottomNavigationView.getMenu().findItem(R.id.uncheckedItem).setChecked(true);
bottomNavigationView.findViewById(R.id.uncheckedItem).setVisibility(View.GONE);
这会取消选中所有菜单项,但默认情况下 BottomNavigationView
会隐藏标题,因为它要显示的菜单项超过 3 个,即使第四个 MenuItem
设置为 GONE
:
所以我的问题仍然存在,是否可以 away/hack 取消 select 所有菜单项并保持其标题显示?
我找到了自己的解决方案,将我的进度与
步骤:
- 更新 proguard-rules.pro 并同步构建
- 创建助手以禁用 BottomNavigationView 切换模式
- 创建要隐藏的项目 Menu.xml
- 膨胀 BottomNavigationView
- 将项目设置为隐藏为已检查已消失
- 使用助手禁用移动模式
输出:
工作代码:
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");
}
}
}
Activity 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;
}
});
}
底部导航Menu.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" />
您的解决方案似乎改变了项目之间的 space
有我的解决方案:
"Just set color of clicked same as color of un-clicked."
例如:
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");
谢谢你的想法。我已经在我的库中实现了它。 我有更好的方法通过反射来做到这一点。所以它不会显示 space.
如果你有兴趣。点击此处: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>
除了我更改了下面标记的两行代码外,这与接受的答案相同。当循环浏览 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");
}
}
mNavigationBottom.getMenu().setGroupCheckable(0, false, true);
要取消选择我创建此扩展程序的所有项目:
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) 使之成为可能。 第三个参数使菜单不排他,然后在循环中更改选中状态。 再次将菜单设置为独占。
最佳答案 mNavigationBottom.getMenu().setGroupCheckable(0, false, true)
对我不起作用。它仍然显示第一项是 selected。
对我有用的是有一个看不见的项目,select,就像你在问题中所做的那样。
将 app:labelVisibilityMode="labeled"
添加到您的 BottomNavigationView
以便所有项目及其标题都保持在视图中。
接受的答案中有一个例外,我们设置了我们无法实现的最大项目code.So我得到的代码比接受的代码更简单,它也适用于最大项目。
我从这里引用 BottomNavigationView 支持的自定义 TextSize 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 的内部 类 使用的默认维度值。所以要小心。
在初始化底部导航视图的 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 设置为 labeled
试试这个,对我有用
<item
android:id="@+id/uncheckedItem"
android:visible="false"
android:title="" />
并设置
bottomNavigationView.getMenu().findItem(R.id.uncheckedItem).setChecked(true);
您将所有菜单项视图显示为未选中;因为选择的 uncheckedItem
是不可见的
希望对您有所帮助。
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);
}