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

时间:2011-07-13 17:41:56

标签: android menu menuitem android-actionbar

我有这样定义的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>

但是,当我使用此选项创建选项菜单时,即使MenuItem的{​​{1}}属性为true,图标也不会以其选中状态显示。

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

正确调用btn_star_off方法,我可以成功更改checked属性:

onOptionsItemSelected()

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

这里有什么我想念的吗?我做错了吗?我无法弄清楚为什么这不能正常工作。

5 个答案:

答案 0 :(得分:34)

根据http://developer.android.com/guide/topics/ui/menus.html

的官方文件
  

注意:图标菜单中的菜单项(来自“选项”菜单)不能   显示复选框或单选按钮。如果你选择在中制作物品   图标菜单可选,您必须手动指示已选中状态   每次状态更改时交换图标和/或文本。

希望它有所帮助。

答案 1 :(得分:11)

如果您仍希望在xml drawable中定义行为(已选中,未选中),则可以通过以下方式实现此目的:

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

答案 2 :(得分:5)

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

经过一些分析,结果表明菜单项的选中状态未正确传播到可绘制对象。这是我想出的解决方案(在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
}

此后,在更改菜单项的选中状态时,您无需执行任何操作,图标应具有自觉性,并在选中状态更改时做出反应。