Состояние проверенного состояния 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, но сам значок не обновляется, чтобы отобразить правильное состояние.
Есть ли что-то, что мне здесь не хватает? Я делаю это неправильно? Я не могу понять, почему это не будет работать правильно.
Ответы
Ответ 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
}
После этого вам не нужно ничего делать при изменении состояния отмеченных пунктов меню, значок должен быть осведомлен о себе и реагировать на каждое изменение проверенного состояния.