【问题标题】:Android Checkable Menu ItemAndroid 可检查菜单项
【发布时间】:2020-07-23 17:49:09
【问题描述】:

我的 Android 应用中有以下菜单布局:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/item1" 
          android:titleCondensed="Options"
          android:title="Highlight Options" 
          android:icon="@android:drawable/ic_menu_preferences" />

   <item android:id="@+id/item2" 
         android:titleCondensed="Persist"
         android:title="Persist" 
         android:icon="@android:drawable/ic_menu_preferences" 
         android:checkable="true" />
</menu>

我的问题是,当我在 Android 模拟器中运行我的应用程序时,第二个菜单项似乎不是“可检查的”。该项目应该有一个绿色的勾号,对吧?表明它是可检查的。

我做错了吗?

【问题讨论】:

  • 您只需要设置不是 android:checkable 为“true”,而是 android:checked !

标签: android android-menu android-checkbox


【解决方案1】:

布局看起来不错。但是你必须在代码中选中和取消选中菜单项。

来自documentation

当一个checkable item被选中时,系统会调用你各自的item-selected回调方法(如onOptionsItemSelected())。您必须在此处设置复选框的状态,因为复选框或单选按钮不会自动更改其状态。您可以使用isChecked() 查询项目的当前状态(就像用户选择它之前一样),然后使用setChecked() 设置选中状态。

【讨论】:

  • 这句话的正上方写着You can apply a default checked state to an item using the android:checked attribute in the &lt;item&gt; element and change it in code with the setChecked() method.哪个是正确的?
  • 我看不出有什么问题。在这句话中说它可能会应用默认检查状态并且检查状态可以更改。在我的报价中说检查状态需要通过代码手动更改。
  • 我对此不好.. 我对菜单项的初始状态感到困惑,是否需要从代码中设置。貌似初始checked状态可以通过xml设置,之后可以通过code随意修改,对吗?
  • 是的,一旦我应用 Java 代码以编程方式检查和取消选中项目,并保持状态,它对我有用,这使 Sergey 成为赢家。谢谢!
  • 感谢您的建议。检查后如何保持菜单打开?
【解决方案2】:

items 包装在group 元素中,如下所示:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="all">
        <item android:id="@+id/item1"
              android:titleCondensed="Options"
              android:title="Highlight Options"
              android:icon="@android:drawable/ic_menu_preferences">
        </item>
        <item android:id="@+id/item2"
              android:titleCondensed="Persist"
              android:title="Persist"
              android:icon="@android:drawable/ic_menu_preferences"
              android:checkable="true">
        </item>
    </group>
</menu>

来自Android docs

android:checkableBehavior 属性接受:

single - 只能检查组中的一项(单选按钮)

all - 可以选中所有项目(复选框)

none - 没有可检查的项目

【讨论】:

  • 您的代码有android:checkable="true" 仅用于一项,android:icon 不适用于可检查的项目
【解决方案3】:

您可以通过将actionViewClass 设置为可检查的小部件(如android.widget.CheckBox)来创建可检查的菜单项

res/menu/menu_with_checkable_menu_item.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_favorite"
        android:checkable="true"
        android:title="@string/action_favorite"
        app:actionViewClass="android.widget.CheckBox"
        app:showAsAction="ifRoom|withText" />
</menu>

如果您将actionLayout 设置为具有样式android.widget.CheckBox 的布局,您甚至可以将其设置为可检查星形

分辨率/布局 /action_layout_styled_checkbox.xml

<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
    style="?android:attr/starStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

res/menu/menu_with_checkable_star_menu_item.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_favorites"
        android:checkable="true"
        android:title="@string/action_favorites"
        app:actionLayout="@layout/action_layout_styled_checkbox"
        app:showAsAction="ifRoom|withText" />
</menu>

设置值

menuItem.setChecked(true/false);

获取价值

menuItem.isChecked()

将 MenuItem 转换为 CheckBox

CheckBox checkBox= (CheckBox) menuItem.getActionView();

【讨论】:

  • 终于 - 工作代码!我花了两个小时才找到有用的东西!菜单不应该这么难!! app:actionViewClass 是菜单中复选框的位置
  • 原来这样其实并不好,因为checkbox不是菜单项的一部分;用户将单击文本并且复选框保持不变 - 我可以通过编程方式更改它。但是,当用户仅触摸复选框时,不会触发该死的 onNavigationItemSelected()。
  • 此时我不建议在导航抽屉中使用菜单 - 如果您需要复选框。各种破事!我将在菜单下手动添加复选框。
  • 我在菜单消失时添加了 300 毫秒 hide 中断延迟(仅当他们单击复选框时).. 我会挖掘代码.. 看起来没问题
【解决方案4】:

我发现最好的解决方案是仅使用我当前 API (27-28) 中的 onOptionsItemSelected() 方法。

@Override
   public boolean onOptionsItemSelected(MenuItem item) 
   {    

//Copy from here...
       int itemId = item.getItemId();

       if(item.isChecked())                          
       { 
           if(R.id.edit_tile_checkbox == itemId)     //Individual checkbox logic
           {   /*TODO unchecked Action*/} 
           item.setChecked(false);                   //Toggles checkbox state.
       }
       else
       {
            if(R.id.edit_tile_checkbox == itemId)    //Individual checkbox logic
            {/*TODO checked Action*/}
            item.setChecked(true);                   //Toggles checkbox state.
       }
//...To here in to your onOptionsItemSelected() method, then make sure your variables are all sweet.

       return super.onOptionsItemSelected(item);
   }

我在这里花了很长时间才得到这个答案。无论出于何种原因,上面的答案都没有帮助(我是一个回归的新手,我确定我可能搞砸了一些东西)。 可能有更好的方法可以做到这一点,因此欢迎提出有益的批评。

【讨论】:

    【解决方案5】:

    回答是因为这里的答案看起来很长而且令人费解。我这里有一些确切的 Kotlin 代码

    在顶部覆盖你的activity并覆盖onMenuItemClick函数,有一个函数来处理按钮点击打开菜单。

    有一个数组或列表保存检查值并在重新创建菜单时设置检查

    注意:此代码不会保持菜单打开,它只确保选中的项目保持选中状态。 我注意到堆栈溢出有很多解决方案,所以如果你想要的话,看看它们

    class exampleActivity : AppCompatActivity(), PopupMenu.OnMenuItemClickListener {
       private var checkChecked = arrayListOf(false,false)
       //some code
    
      fun clickBTN(v: View){
            val popup = PopupMenu(this,v)
            popup.setOnMenuItemClickListener(this)
            popup.inflate(R.menu.yourmenufilename)
            //assuming you have 2 or more menu items
            popup.menu[0].isChecked = checkChecked[0]
            popup.menu[1].isChecked = checkChecked[1]
            popup.show()
      }
    
      override fun onMenuItemClick(item: MenuItem?): Boolean {
         when(item?.itemID){
            R.id.item0 -> {
                    item.isChecked = !item.isChecked
                    checkChecked[0] = item.isChecked
                    return true
            }
            R.id.item1 -> {
                    item.isChecked = !item.isChecked
                    checkChecked[1] = item.isChecked
                    return true
            }
      }
    }
    

    当然,在 XML 中你应该有你的按钮和菜单设置。示例菜单在这里

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/item0"
            android:title="@string/hi"
            android:checkable="true"/>
        <item android:id="@+id/item1"
            android:title="@string/yo"
            android:checkable="true"/>
    </menu>
    

    【讨论】:

      【解决方案6】:

      这可能取决于主题,但我的菜单没有显示复选框。我找到了this

      注意:图标菜单中的菜单项不能显示复选框或单选框 按钮。如果您选择将图标菜单中的项目设为可勾选,则 您必须亲自通过交换图标和/或 每次状态在开和关之间变化时的文本。

      【讨论】:

        【解决方案7】:

        对于以编程方式添加菜单项,

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
        
            menu.add("Item1").setActionView(R.layout.action_layout_checkbox).setCheckable(true);
            return super.onCreateOptionsMenu(menu);
        }
        

        res/layout /action_layout_checkbox.xml

        <CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        

        【讨论】:

          【解决方案8】:

          阅读本文

          如前所述,“人工检查”只是冰山一角。它以如此快的速度闪现菜单用户看不到任何事情发生,而且它非常反直觉,令人沮丧,并且实际上完全是废话。 REAL TASK(因此)允许复选框事件被用户的头脑消化。

          好消息:这可以完成并且确实有效,这就是您的做法。 @TouchBoarder 做得最好,所以我会复制他的代码。然后开发它。

          这个想法是检测复选框是否被点击,然后(并且只有当那个被选中时)稍微抑制菜单删除,添加一个 500 毫秒的计时器然后关闭菜单,这会给出复选框的“滴答”动画跑的时间并创造正确的“感觉”

          <menu xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto">
              <item
                  android:id="@+id/action_favorite"
                  android:checkable="true"
                  android:title="@string/action_favorite"
                  app:actionViewClass="android.widget.CheckBox"
                  app:showAsAction="ifRoom|withText" />
          </menu>
          

          然后你像往常一样做这个方法,但你确保你添加了所有这些额外的凹凸

          public boolean onCreateOptionsMenu(Menu menu) {
              // Inflate the bottom bar and the top bar (weird)
              BottomAppBar bottomBar = findViewById(R.id.bottom_app_bar_help);
              Menu bottomMenu = bottomBar.getMenu();
              getMenuInflater().inflate(R.menu.bottom_nav_menu, bottomMenu);
              for (int i = 0; i < bottomMenu.size(); i++) {
                  bottomMenu.getItem(i).setOnMenuItemClickListener(item -> {
                      if (item.getItemId()==R.id.action_favorite){
                          item.setChecked(!item.isChecked());
                          // Keep the popup menu open
                          item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
                          item.setActionView(new View(frmMain.this));
                          item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
                              @Override
                              public boolean onMenuItemActionExpand(MenuItem item) {
                                  final Handler handler = new Handler();
                                  handler.postDelayed(() -> bottomMenu.close(), 500);
                                  return false;
                              }
          
                              @Override
                              public boolean onMenuItemActionCollapse(MenuItem item) {
                                  final Handler handler = new Handler();
                                  handler.postDelayed(() -> bottomMenu.close(), 500);
                                  return false;
                              }
                          });
                          return false;
                      }
                      else {
                          return onOptionsItemSelected(item);
                      }
                  });
              }
              return true;
          }
          

          其他菜单事件在这里

          public boolean onOptionsItemSelected(MenuItem item) {
              // Bottom Bar item click
              try {
                  switch (item.getItemId()) {
                      case R.id.mnuExit:
                          MenuClick(ClickType.LOGOUT);
                          return true;
          
                      case R.id.mnuList:
                          MenuClick(ClickType.LIST);
                          return true;
                      default:
                          return super.onOptionsItemSelected(item);
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              }
              return super.onOptionsItemSelected(item);
          }
          

          【讨论】:

            【解决方案9】:

            我在菜单中有两个项目,并在menu.xml 文件中设置为可检查,如下所示

                <item
                    android:id="@+id/A"
                    android:title="A"
                    app:showAsAction="never"
                    android:checkable="true"/>
                <item
                    android:id="@+id/B"
                    android:title="B"
                    app:showAsAction="never"
                    android:checkable="true"/> 
            

            菜单复选框的逻辑如下。

            @Override
            public boolean onOptionsItemSelected(@NonNull MenuItem item) {
            
                switch (item.getItemId()) {
                    case R.id.A:
                       //logic goes here
            
            
                        if(item.isChecked())
                        {
                         //logic is it is checked
                         item.setChecked(false);
                        }
                        else
                        {
                           //logic is it is not checked
                            item.setChecked(true);
                        }
                        return true;
                    case R.id.B:
                     //logic for second checkbox goes here
            
            
                        if(item.isChecked())
                        {
                         //logic is it is checked
                            item.setChecked(false);
                        }
                        else
                        {
                         //logic is it is not checked
                            item.setChecked(true);
                        }
                        return true;
                    default:
                        return super.onOptionsItemSelected(item);
                }
            

            【讨论】:

              猜你喜欢
              • 2011-03-14
              • 1970-01-01
              • 2014-06-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多