MenuItem 的选中状态未通过其图标正确显示

发布于 2024-11-19 15:58:33 字数 1570 浏览 3 评论 0原文

我以这种方式定义了 MenuItem:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_starred"
        android:icon="@drawable/btn_star"
        android:title="@string/description_star"
        android:checkable="true"
        android:checked="true"
        android:orderInCategory="1"
        android:showAsAction="always" />
</menu>

并且以这种方式定义了 btn_star.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item 
        android:state_checked="false" 
        android:drawable="@drawable/btn_star_off_normal" />
    <item 
        android:state_checked="true"
        android:drawable="@drawable/btn_star_on_normal" />
</selector>

但是,当我使用此方法创建选项菜单时,图标永远不会以选中状态显示,即使 MenuItemisChecked() 属性为 true。

我正在使用 ActionBarSherlock 控件,但是,如果我只是创建一个普通的选项菜单并调用,我会得到相同的结果setChecked(true)。无论项目的选中状态如何,它仍然显示 btn_star_off 可绘制对象。

onOptionsItemSelected() 方法被正确调用,并且我可以成功更改选中的属性:

@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if(item.isCheckable()) {
            item.setChecked(!item.isChecked());
        }
        return super.onOptionsItemSelected(item);
}

在此处设置断点显示 isChecked 属性正在更改,但图标本身未更新以反映正确的状态。

我在这里缺少什么吗?我这样做错了吗?我不明白为什么这不能正常工作。

I have MenuItem defined this way:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_starred"
        android:icon="@drawable/btn_star"
        android:title="@string/description_star"
        android:checkable="true"
        android:checked="true"
        android:orderInCategory="1"
        android:showAsAction="always" />
</menu>

and btn_star.xml defined this way:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item 
        android:state_checked="false" 
        android:drawable="@drawable/btn_star_off_normal" />
    <item 
        android:state_checked="true"
        android:drawable="@drawable/btn_star_on_normal" />
</selector>

When I create an options menu using this, however, the icon is never shown in its checked state, even if the MenuItem's isChecked() property is true.

I'm using the ActionBarSherlock control, however, I'm getting the same result if I simply create a normal options menu and call setChecked(true). It still displays the btn_star_off drawable regardless of the checked state of the item.

The onOptionsItemSelected() method is being called correctly, and I can successfully change the checked property:

@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if(item.isCheckable()) {
            item.setChecked(!item.isChecked());
        }
        return super.onOptionsItemSelected(item);
}

Setting a breakpoint here shows the isChecked property being changed, but the icon itself is not updated to reflect the correct state.

Is there something I'm missing here? Am I doing this incorrectly? I can't figure out why this wouldn't be working correctly.

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

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

发布评论

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

评论(5

花海 2024-11-26 15:58:33

根据官方文档 http://developer.android.com/guide/topics /ui/menus.html

注意:图标菜单(来自选项菜单)中的菜单项不能
显示复选框或单选按钮。如果您选择在
图标菜单可检查,您必须通过以下方式手动指示检查状态
每次状态改变时交换图标和/或文本。

希望它有帮助。

According to the official document at http://developer.android.com/guide/topics/ui/menus.html

Note: Menu items in the Icon Menu (from the Options Menu) cannot
display a checkbox or radio button. If you choose to make items in the
Icon Menu checkable, you must manually indicate the checked state by
swapping the icon and/or text each time the state changes.

Hope it helps.

氛圍 2024-11-26 15:58:33

如果您仍然希望在 xml 可绘制对象中定义行为(选中或未选中),这是实现此目的的一种方法:

if (item.getItemId()==R.id.menu_item){
    item.setChecked(!item.isChecked());
    StateListDrawable stateListDrawable = (StateListDrawable) getResources().getDrawable(R.drawable.selector_drawable);
    int[] state = {item.isChecked()?android.R.attr.state_checked:android.R.attr.state_empty};
    stateListDrawable.setState(state);
    item.setIcon(stateListDrawable.getCurrent());
}

If you still want to have the behavior (checked, not checked) defined in a xml drawable, this is one way you could accomplish this:

if (item.getItemId()==R.id.menu_item){
    item.setChecked(!item.isChecked());
    StateListDrawable stateListDrawable = (StateListDrawable) getResources().getDrawable(R.drawable.selector_drawable);
    int[] state = {item.isChecked()?android.R.attr.state_checked:android.R.attr.state_empty};
    stateListDrawable.setState(state);
    item.setIcon(stateListDrawable.getCurrent());
}
森林散布 2024-11-26 15:58:33

更简单的方法(没有 xml-states 文件):

configChecked = !configChecked;
item.setChecked(configChecked);
item.setIcon(configChecked ? R.drawable.check_on : R.drawable.check_off);

A bit simpler way (without xml-states file):

configChecked = !configChecked;
item.setChecked(configChecked);
item.setIcon(configChecked ? R.drawable.check_on : R.drawable.check_off);
箜明 2024-11-26 15:58:33

问题有点老了,但我最近偶然发现了这个问题。

经过一些分析后发现,菜单项的选中状态没有正确传播到可绘制对象。这是我想出的解决方案(在 Kotlin 中)。

确保您的 menuItem 使用状态列表可绘制对象(如问题中的 btn_star.xml ),然后创建一个可绘制包装器类:

/** Fixes checked state being ignored by injecting checked state directly into drawable */
class CheckDrawableWrapper(val menuItem: MenuItem) : DrawableWrapper(menuItem.icon) {
    // inject checked state into drawable state set
    override fun setState(stateSet: IntArray) = super.setState(
        if (menuItem.isChecked) stateSet + android.R.attr.state_checked else stateSet
    )
}

/** Wrap icon drawable with [CheckDrawableWrapper]. */
fun MenuItem.fixCheckStateOnIcon() = apply { icon = CheckDrawableWrapper(this) }

最后一步是用包装的可绘制对象替换可绘制菜单项:

override fun onCreateOptionsMenu(menu: Menu) : Boolean{
    menuInflater.inflate(R.menu.menu_main, menu)
    menu.findItem(R.id.menu_starred).fixCheckStateOnIcon()
    /** ...  */
    return true
}

之后,在更改菜单项的选中状态时,您不需要执行任何操作,图标应该具有自我意识,并在选中状态发生变化时做出反应。

Question is a bit old but I stumbled upon this problem recently.

After some analyzing it turns out that checked state of menu item is not being properly propagated down to the drawable. Here's the solution I came up with (in Kotlin).

Ensure your menuItem is using a state list drawable (like btn_star.xml from question), then create a drawable wrapper class:

/** Fixes checked state being ignored by injecting checked state directly into drawable */
class CheckDrawableWrapper(val menuItem: MenuItem) : DrawableWrapper(menuItem.icon) {
    // inject checked state into drawable state set
    override fun setState(stateSet: IntArray) = super.setState(
        if (menuItem.isChecked) stateSet + android.R.attr.state_checked else stateSet
    )
}

/** Wrap icon drawable with [CheckDrawableWrapper]. */
fun MenuItem.fixCheckStateOnIcon() = apply { icon = CheckDrawableWrapper(this) }

Last step is replacing menu items drawable with wrapped drawable:

override fun onCreateOptionsMenu(menu: Menu) : Boolean{
    menuInflater.inflate(R.menu.menu_main, menu)
    menu.findItem(R.id.menu_starred).fixCheckStateOnIcon()
    /** ...  */
    return true
}

After that you don't need to do anything when changing menu items checked state, icon should be self aware and react whenever checked state changes.

枕梦 2024-11-26 15:58:33
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/fav"
        android:title=""
        app:showAsAction="ifRoom"
        android:orderInCategory="1"
        android:icon="@drawable/ic_favorite_black_unselectd"
        android:checked="false" />
    <item android:id="@+id/share"
        android:title=""
        app:showAsAction="ifRoom"
        android:orderInCategory="2"
        android:icon="@drawable/ic_share_black" />
</menu>

//and in java...

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.fav:
            boolean mState = !item.isChecked();
            item.setChecked(mState);
            item.setIcon(mState ? getResources().getDrawable(R.drawable.ic_favorite_black_selected) : getResources().getDrawable(R.drawable.ic_favorite_black_unselectd));
            Toast.makeText(this, "" + item.isChecked(), Toast.LENGTH_SHORT).show();
            return true;
        case R.id.share:
            return true;
    }
    return super.onOptionsItemSelected(item);
}
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/fav"
        android:title=""
        app:showAsAction="ifRoom"
        android:orderInCategory="1"
        android:icon="@drawable/ic_favorite_black_unselectd"
        android:checked="false" />
    <item android:id="@+id/share"
        android:title=""
        app:showAsAction="ifRoom"
        android:orderInCategory="2"
        android:icon="@drawable/ic_share_black" />
</menu>

//and in java...

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.fav:
            boolean mState = !item.isChecked();
            item.setChecked(mState);
            item.setIcon(mState ? getResources().getDrawable(R.drawable.ic_favorite_black_selected) : getResources().getDrawable(R.drawable.ic_favorite_black_unselectd));
            Toast.makeText(this, "" + item.isChecked(), Toast.LENGTH_SHORT).show();
            return true;
        case R.id.share:
            return true;
    }
    return super.onOptionsItemSelected(item);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文