【问题标题】:Why do checkable menu items not display checkboxes为什么可检查的菜单项不显示复选框
【发布时间】:2021-12-04 08:49:21
【问题描述】:

NavigationView菜单:

<?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">
   <group android:checkableBehavior="all">
        <item
            android:id="@+id/itemFoo1"
            android:checkable="true"
            android:title="Foo1" />
        <item
            android:id="@+id/itemFoo2"
            android:checkable="true"
            android:title="Foo2" />
    </group>
</menu>

Android Studio 中的设计器显示复选框:

但是,该应用不显示复选框:

谁能提供线索?

使用菜单的布局:

<com.google.android.material.navigation.NavigationView
    android:id="@+id/navigationView"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="end"
    app:menu="@menu/activity_foo_view"/>

【问题讨论】:

  • 设计器显示该菜单资源被用作菜单,而不是用于导航。也许导航不支持可检查的项目(部分原因是......导航项目有一个复选框意味着什么?)。
  • @CommonsWare 这正是我一直在怀疑的——我现在面临的所有菜单项问题都可能与 NavigationView 有关。在这种情况下,我使用 NavigationView 作为操作菜单。也许我应该改变这个方案。
  • Checkable != Checkbox。仅仅因为您可以在某事上调用setChecked() 并不意味着它必须显示Checkbox。这纯粹是一个设计决定,属于基于 SO 的意见。
  • @MikeM。我认为我的问题的标题很难反映我的初衷。我主要好奇为什么设计器显示 checkboxex 而应用程序没有。我希望这方面的提示能让我了解我在菜单方面面临的其他问题。
  • 啊,好吧,我明白你在说什么了。是的,AFAIK 设计师只能将菜单预览为下拉弹出样式。即使它足够聪明地知道您在 NavigationView 中使用它,它仍然不会在那里显示。

标签: android android-menu drawerlayout android-navigationview


【解决方案1】:

NavigationView 的默认行为是一次选择一个项目;例如,这通常会在抽屉布局中选择一个片段。

正如 Mike M 在 cmets 中指出的那样;使项目可检查并不意味着它是CheckBox

因此,您必须在菜单项中添加一个CheckBox,并且有两个选项可以做到这一点:

  • 选项 1: 使用 CheckBox 作为 app:actionViewClass

  • 选项 2: 使用带有 app:actionLayout 的自定义布局:检查 this answer 以了解该情况

CheckBox 用作app:actionViewClass

<?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">
   <group android:checkableBehavior="all">
        <item
            android:id="@+id/itemFoo1"
            android:checkable="true"
            app:actionViewClass="android.widget.CheckBox"
            android:title="Foo1" />
        <item
            android:id="@+id/itemFoo2"
            android:checkable="true"
            app:actionViewClass="android.widget.CheckBox"
            android:title="Foo2" />
    </group>
</menu>

点击复选框将切换其状态,但点击项目文本不会;这可以通过获取 menuItem ActionView 并使用 setChecked() 切换 CheckBox 以编程方式解决:

private final NavigationView.OnNavigationItemSelectedListener navViewlistener = new NavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {

        int id = item.getItemId();

        if (id == R.id.itemFoo1 || id == R.id.itemFoo2) {
            CheckBox actionView = (CheckBox) item.getActionView();
            actionView.setChecked(!actionView.isChecked()); // Toggle the CheckBox
        }

        return true;
    }
};

navView.setNavigationItemSelectedListener(navViewlistener);

更新

我用了一段时间 app:actionViewClass="android.widget.CheckBox"。主要问题是复选框独立于项目。单击它不会触发NavigationItemSelectedListener。这就是我寻找新方法的主要原因。

这是对的;我们可以通过在选中/取消选中持有 CheckBox 时触发 MenuItem 点击事件以编程方式解决此问题。

但主要问题是,它可能导致无限循环;当我们选中/取消选中 onNavigationItemSelected 中的 CheckBox 时;这将触发另一个MenuItem 点击等等。

所以,这里是 mIsCheckBoxClick 布尔值,并且在调用 setChecked() 之前停止 CheckBox 侦听器,然后重新附加它们;所有这些都是为了避免循环:

private boolean mIsCheckBoxClick;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ....... add your code

    // Enable CheckBox listeners at the NavView menu items by default 
    addFooListeners(navView, true);
}

private void addFooListeners(final NavigationView navView, boolean enabled) {
    adjustNavViewItemListener(navView.getMenu().findItem(R.id.itemFoo1), navView, enabled);
    adjustNavViewItemListener(navView.getMenu().findItem(R.id.itemFoo2), navView, enabled);
}

private void adjustNavViewItemListener(final MenuItem item, final NavigationView navView, boolean enabled) {
    final CheckBox fooChBox = (CheckBox) item.getActionView();
    CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            mIsCheckBoxClick = true;
            navView.getMenu().performIdentifierAction(item.getItemId(), 0); // perform a click on MenuItem to trigger OnNavigationItemSelectedListener
        }
    };
    fooChBox.setOnCheckedChangeListener(enabled ? listener : null);
}


private final NavigationView.OnNavigationItemSelectedListener navViewlistener = new NavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {

        int id = item.getItemId();

        if (id == R.id.itemFoo1 || id == R.id.itemFoo2) {
            
            // Loop prevention check
            if (!mIsCheckBoxClick) {
                CheckBox actionView = (CheckBox) item.getActionView();
            
                // Stop the CheckBox listeners
                addFooListeners(navView, false);
                
                actionView.setChecked(!actionView.isChecked());
                
                // Reattach the CheckBox listeners
                addFooListeners(navView, true);
            }
            mIsCheckBoxClick = false;           
        }

        return true;
    }
};

【讨论】:

  • 非常感谢详细的解决方案。我实际上面临着菜单项的一系列问题。我问了这个特定的问题,希望提示可以使我了解所有问题的原因。我用了一段时间 app:actionViewClass="android.widget.CheckBox"。主要问题是复选框独立于项目。单击它不会触发 NavigationItemSelectedListener。这是我寻求新方法的主要原因。
  • @Hong 完全正确.. 两者都是独立的,几乎所有东西都可以定制;我刚刚更新了在复选框点击时触发NavigationItemSelectedListener 回调的答案;希望它能为你解决这个问题
猜你喜欢
  • 2012-01-05
  • 1970-01-01
  • 2020-11-15
  • 1970-01-01
  • 1970-01-01
  • 2014-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多