Android 可检查菜单项

发布于 2024-11-12 06:08:44 字数 699 浏览 5 评论 0原文

我的 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 模拟器中运行我的应用程序时,第二个菜单项似乎不是“可检查的”。该项目应该有一个绿色的勾号,对吗?表明其可检查。

我做错了什么吗?

I have the following menu layout in my Android app:

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

My problem is that the second menu item doesn't appear to be "checkable" when I run my app in the Android emulator. There should be a green tick about the item, right? To indicate that its checkable.

Am I doing something wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

忘东忘西忘不掉你 2024-11-19 06:08:44

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

来自文档

当选择了可检查的项目时,系统会调用相应的项目选择回调方法(例如onOptionsItemSelected())。您必须在此处设置复选框的状态,因为复选框或单选按钮不会自动更改其状态。您可以使用 isChecked() 然后使用 setChecked()

Layout looks right. But you must check and uncheck menu item in code.

From the documentation:

When a checkable item is selected, the system calls your respective item-selected callback method (such as onOptionsItemSelected()). It is here that you must set the state of the checkbox, because a checkbox or radio button does not change its state automatically. You can query the current state of the item (as it was before the user selected it) with isChecked() and then set the checked state with setChecked().

玩心态 2024-11-19 06:08:44

item 包裹在 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 文档

android:checkableBehavior 属性接受:

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

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

无 - 没有可检查的项目

Wrap the items in a group element, like this:

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

From the Android docs:

The android:checkableBehavior attribute accepts either:

single - Only one item from the group can be checked (radio buttons)

all - All items can be checked (checkboxes)

none - No items are checkable

盛夏已如深秋| 2024-11-19 06:08:44

您可以通过将 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 res/layout 的
/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();

You can create a checkable menu item by setting the actionViewClass to a checkable widget like 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>

And you can can even style it to be a checkable star if you set actionLayout to a layout with a styled android.widget.CheckBox

res/layout
/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>

To set the value

menuItem.setChecked(true/false);

To get the value

menuItem.isChecked()

Cast MenuItem to CheckBox

CheckBox checkBox= (CheckBox) menuItem.getActionView();
甩你一脸翔 2024-11-19 06:08:44

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

@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);
   }

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

I've found that the best solution was to just use the onOptionsItemSelected() method as of my current API (27-28).

@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);
   }

I spent way to long on here for this answer. and for whatever reason, the answers above didn't help (I'm a returning newbie I probably mucked something up I'm sure).
There could be a better way of doing this so helpful criticism is welcomed.

自由如风 2024-11-19 06:08:44

阅读本文

正如所说,“手动检查”只是冰山一角。它闪现菜单的速度如此之快,用户看不到任何事情发生,而且非常违反直觉,令人沮丧,而且实际上是一派胡言。 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);
}

READ THIS

As has been said the "manual checking" is only the tip of the iceberg. It flashes the menu away so fast the users don't see anything happen and it is very counter intuitive, frustrating, and effectively utter crap. The REAL TASK (therefore) is allowing the check box event to be digested by the users mind.

Good news: this can be done and it does work and this is how you do it. @TouchBoarder had it best so I will copy his code. then develop it.

the idea is to detect if the checkbox is clicked, then (and only if that one is picked) slightly suppress the menu removal, add a timer for 500ms then close the menu, this give the "tick" animation of the checkbox time to run and creates the right "feel"

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

then you make this method as usual, but you make sure you add all this extra bumpf

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

the other menu events are here

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);
}
为你拒绝所有暧昧 2024-11-19 06:08:44

回答是因为这里的答案看起来又长又复杂。我在这里有一些确切的 Kotlin 代码

覆盖顶部的活动并覆盖 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>

Answering because the answers here seem long and convoluted.. I have some exact Kotlin code here

Override your activity at the top and override the function onMenuItemClick, Have a function to handle the button click to open the menu.

Have an array or list which holds the checked value and sets the check when the menu is re-created

Note: This code does not keep the menu open, It only ensures that checked items remain checked.
I noted there are lots of solutions to that on stack overflow, so have a look at them if that's what you desire

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

of course in XML you should have your Button and Menu setup. An example menu is here

<?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>
终止放荡 2024-11-19 06:08:44

这可能取决于主题,但我的菜单没有显示复选框。我发现这个

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

This may be theme dependant but my menu didn't show a checkbox. I found this :

Note: Menu items in the Icon Menu cannot display a checkbox or radio
button. If you choose to make items in the Icon Menu checkable, then
you must personally indicate the state by swapping the icon and/or
text each time the state changes between on and off.

感情废物 2024-11-19 06:08:44

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

@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" />

For Adding Menu items Programmatically,

@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" />
素手挽清风 2024-11-19 06:08:44

我在菜单中有两个项目,并在 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);
    }

I have two items in the menu and set to checkable in menu.xml file like below

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

and logic for the menu checkboxes is below.

@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);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文