Подтвердить что ты не робот

Состояние проверенного состояния MenuItem не отображается корректно по значку

У меня есть 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 isChecked() равно 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, но сам значок не обновляется, чтобы отобразить правильное состояние.

Есть ли что-то, что мне здесь не хватает? Я делаю это неправильно? Я не могу понять, почему это не будет работать правильно.

4b9b3361

Ответ 1

Согласно официальному документу в http://developer.android.com/guide/topics/ui/menus.html

Примечание. Элементы меню в меню значков (из меню параметров) не могут установите флажок или переключатель. Если вы решите сделать элементы в Меню "Значок", , вы должны вручную указать заменяя значок и/или текст при каждом изменении состояния.

Надеюсь, что это поможет.

Ответ 2

Если вы все еще хотите, чтобы поведение (отмечено, не отмечено) определено в 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());
}

Ответ 3

Немного проще (без файла xml-states):

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

Ответ 4

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

Ответ 5

Вопрос немного старый, но я недавно наткнулся на эту проблему.

После некоторого анализа выясняется, что проверенное состояние пункта меню не распространяется должным образом до объекта рисования. Вот решение, которое я нашел (в Котлине).

Убедитесь, что ваш 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
}

После этого вам не нужно ничего делать при изменении состояния отмеченных пунктов меню, значок должен быть осведомлен о себе и реагировать на каждое изменение проверенного состояния.