取消选中BottomNavigationView中没有虚拟物品或反射的所有物品

我正在尝试从设计库中使用BottomNavigationView。 除了我希望每个导航项目启动一个活动外,一切正常,因此我想取消选中导航栏中的所有项目,使它们看起来相同。 我已经尝试了几种解决方案,其中大部分都不起作用,而最后一种解决方案确实有效,但感觉非常不好。

首先我做了这个:

ViewGroup nav = (ViewGroup) bottomNav; for(int i=0; i < nav.getChildCount(); i++) { nav.getChildAt(i).setSelected(false); } 

这似乎什么都不做。

然后我试着:

 int size = bottomNav.getMenu().size(); for (int i = 0; i < size; i++) { bottomNav.getMenu().getItem(i).setChecked(false); } 

其中只有最后一项检查,而不是第一个。

最后我尝试在菜单中添加一个虚拟物品,

 bottomNav.getMenu().findItem(R.id.dummmy_item).setChecked(true); bottomNav.findViewById(R.id.dummmy_item).setVisibility(View.GONE); 

这几乎可以工作,但它隐藏了下面的标题,这对我的情况来说很重要。

然后我找到了这个答案: https : //stackoverflow.com/a/41372325/4888701并编辑我的上述解决方案,包括。 具体而言,我添加了proguard规则,并使用了确切的帮助类,并调用该方法。 它看起来是正确的,似乎工作。 但是对我来说感觉不好,因为:

  1. 我正在使用一个虚拟菜单项目,以便不能查看可见项目
  2. 它增加了相当多的代码应该是一个小的视觉修正。
  3. 我已经读过,如果可能,应该避免反思。

有没有其他的,最好是简单的方法来实现这个,或者这是最好的,我们有当前版本的图书馆?

(作为一个便笺,我想知道在这个解决方案中的proguard规则是否有必要,它是做什么的?我对proguard一无所知,但是这个项目是从其他人启用的。

经过大量的试验和错误,这对我来说(使用Kotlin)

 (menu.getItem(i) as? MenuItemImpl)?.let { it.isExclusiveCheckable = false it.isChecked = it.itemId == actionId it.isExclusiveCheckable = true } 

如果我已经正确地理解了你的问题(这可能我没有),那么更好的解决方案可能是翻转这个问题。 这些是我对你的问题的假设:

  • 你有一系列的活动
  • 每个Activity都有自己的BottomNavigationView
  • 当您单击一个活动的BNV时,被点击的项目被选中
  • 你想取消选择被点击的项目,因为当新的活动开始没有被选中

如果我的假设是正确的,有两个更好的解决方案:

  1. 使用片段不活动( 推荐
    • 他们BNV停留在一个活动中,活动中的片段发生变化
  2. 不要取消选中的项目
    • 每个活动开始时选择正确的瓷砖匹配

也就是说,如果你真的想这样做,我认为下面的代码可以实现它,只要改变受影响的项目就可以了。 (只要有可能,你应该避免反射,这通常表明你的设计存在另一个架构问题)

 bnv.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { item.getActionView().setSelected(false); return false; } }); 

我知道这个问题不要使用反射,但是,我还没有找到另一种方式来获得所需的效果,而不使用它。 有一个代码修复允许在git repo中禁用转换模式,但谁知道何时会被释放。 所以暂时(26.0.1),这个代码适合我。 也有人说不使用反射的原因是因为它在Android上很慢(特别是在较旧的设备上)。 但是,对于这一个电话来说,这不会对性能产生影响。 当你解析/序列化大量的数据时,你应该避免它。

需要proguard规则的原因是因为proguard混淆了你的代码。 这意味着它可以改变方法名称,截断名称,分解类和其他任何它认为合适的东西,以防止有人能够阅读你的源代码。 这个规则可以防止这个字段变量的名称发生改变,所以当你通过反射调用它时,它仍然存在。

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); // <-- Changed this line item.setCheckable(false); // <-- Added this line } } 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"); } }