Выбор ListView остается постоянным после выхода из режима выбора
У меня есть подкласс ListView, который я разрешаю, когда активна панель действия контекста (CAB). CAB устанавливается как обратный вызов события onItemLongClick
:
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate a menu resource providing context menu items
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(context_menu, menu);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
return true;
}
Это прекрасно, и ListView работает так, как ожидалось, когда выделенный элемент остается выделенным при касании.
Когда я закрываю CAB, , я хочу, чтобы ListView возвращался в нормальный режим (т.е. сенсорный режим). Проблема в том, что последний выбранный элемент остается неопределенным, независимо от того, какие методы я пытаюсь его очистить:
public void onDestroyActionMode(ActionMode mode) {
//Unselect any rows
ListView lv = getListView();
lv.clearChoices(); // Has no effect
lv.setChoiceMode(ListView.CHOICE_MODE_NONE); // Has no effect on the highlighted item
lv.setFocusable(false); // Has no effect
lv.setSelection(0); // Has no effect
mActionMode = null;
}
Любые предложения?
Ответы
Ответ 1
Основная причина проблемы заключается в том, что после переключения режима ListView
на CHOICE_MODE_NONE
среда оптимизирует операцию clear, поскольку она больше не поддерживает "выбор". Я немного улучшил описанные выше обходные пути, очистив состояние выбора вручную, а затем установив режим с задержкой, поэтому структура будет иметь свою очередь, чтобы очистить состояние, прежде чем переключать режим на CHOICE_MODE_NONE
.
final ListView lv = getListView();
lv.clearChoices();
for (int i = 0; i < lv.getCount(); i++)
lv.setItemChecked(i, false);
lv.post(new Runnable() {
@Override
public void run() {
lv.setChoiceMode(ListView.CHOICE_MODE_NONE);
}
});
Ответ 2
Я столкнулся с той же проблемой, и поскольку запрос макета не решает проблему для меня, либо я реализовал небольшой хак, который работает для меня. Возможно, это та же проблема, потому что я переключаюсь между CHOICE_MODE_SINGLE
и CHOICE_MODE_NONE
.
Когда закон заканчивается, я вызываю этот фрагмент кода. clearChoices
гарантирует, что все элементы больше не будут проверяться (внутренне). Итерация над представлениями гарантирует, что все видимые в настоящее время виды reset и больше не отмечены.
mListView.clearChoices();
for (int i = 0; i < mListView.getChildCount(); i++) {
((Checkable) mListView.getChildAt(i)).setChecked(false);
}
mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
Ответ 3
Посмотрев на исходный код ListView, единственный способ обойти это - установить ListView в CHOICE_MODE_NONE, а затем повторно назначить ListAdapter (который очищает внутренний список выбора независимо от режима выбора)
то есть. в ListFragment/ListActivity
getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
getListView().setAdapter(getListAdapter())
Ответ 4
У меня была эта проблема в API Level 17
и она решила:
listView.clearChoices();
listView.invalidateViews();
Ответ 5
Для меня кажется, что принятый ответ не работает для невидимых элементов, и нет необходимости называть
for (int i = 0; i < lv.getCount(); i++)
lv.setItemChecked(i, false);
вместо этого просто вызовите
lv.requestLayout();
Чтобы полностью решить мою проблему, я вызываю
lv.clearChoices();
lv.requestLayout();
в onDestroyActionMode()
и вызовите
lv.setItemChecked(position, false)
в onItemClick()
, если он не находится в ActionMode
Однако я не подтвердил, вызовет ли вызов setItemChecked()
некоторые проблемы с производительностью
Ответ 6
Это зарегистрировано как ошибка AOSP, но по какой-либо причине помечается как устаревшая.
Обычно вы ожидаете, что это сработает:
getListView().clearChoices();
getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
К сожалению, это не так. Отключение режима выбора настроек до ни одного в следующем макете будет работать:
getListView().clearChoices();
getListView().post(new Runnable() {
@Override
public void run() {
getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
}
});
Ответ 7
Я пробовал все описанные выше подходы, но никто из них не работает для меня. Наконец, я решил применить следующее обходное решение. Основная идея заключается в том, что
В многомодовом режиме вместо повторного использования "кэшированного" представления мы создадим совершенно новое представление. Неэффективен, но, по крайней мере, "частично" решает мою проблему.
Вот код моего настроенного ArrayAdapter
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Key to solve this problem. When we are in multimode, we will not reusing the cached view.
View rowView = this.multimode ? null : convertView;
if (rowView == null) {
LayoutInflater inflater = activity.getLayoutInflater();
rowView = inflater.inflate(R.layout.watchlist_row_layout, null);
ViewHolder viewHolder = new ViewHolder();
viewHolder.textView0 = (TextView) rowView.findViewById(R.id.text_view_0);
viewHolder.textView1 = (TextView) rowView.findViewById(R.id.text_view_1);
viewHolder.textView2 = (TextView) rowView.findViewById(R.id.text_view_2);
rowView.setTag(viewHolder);
}
Кроме того, я уверен, что в ActionMode.Callback есть следующий код, хотя я не уверен, насколько он помогает.
@Override
public void onDestroyActionMode(ActionMode mode) {
MyFragment.this.myArrayAdapter.setMultimode(false);
// http://stackoverflow.com/questions/9754170/listview-selection-remains-persistent-after-exiting-choice-mode
// Using View.post is the key to solve the problem.
final ListView listView = MyFragment.this.getListView();
listView.clearChoices();
for (int i = 0, ei = listView.getChildCount(); i < ei; i++) {
listView.setItemChecked(i, false);
}
listView.post(new Runnable() {
@Override
public void run() {
listView.setChoiceMode(ListView.CHOICE_MODE_NONE);
}
});
actionMode = null;
}
Боковое примечание
Использование пары MultiChoiceModeListener с CHOICE_MODE_MULTIPLE_MODAL приведет к исчезновению этой ошибки. Однако для устройства ниже уровня API 11 не сможет использовать это решение.
Ответ 8
Я знаю, что на это был дан ответ, но выше ответы все же дали мне проблемы с кэшированными/переработанными представлениями, которые поддерживает ListView, которые не обновляли его при прокрутке назад в представлении.
Итак, приведенное выше решение немного меняется:
lv.clearChoices();
ArrayList<View> list = new ArrayList<View>();
lv.reclaimViews(list);
for (View view : list) {
((Checkable) view).setChecked(false);
}
lv.setChoiceMode(lv.CHOICE_MODE_NONE);
Это лучше, чем использование getChildAt (i), потому что этот метод jusg дает вам просматриваемые в настоящее время виды и не учитывает внутренние кэшированные представления, которые не видны.
Ответ 9
Я обнаружил, что здесь работают только два метода (API 19)
:
- Сброс адаптера списка, что нежелательно, поскольку оно возвращается в начало списка;
- Установка режима выбора
CHOICE_MODE_NONE
в new Runnable
Если режим выбора изменен без использования listView.post(new Runnable())
, он не работает. Может ли кто-нибудь объяснить мне, почему это так?
Извинения за не комментирование; У меня нет репутации.
Спасибо.
Ответ 10
Не уверен, что слишком поздно просто хочет поделиться. Я создал намерение на той же странице, чтобы после захвата данных щелкнула новую страницу без какой-либо нажатой настойчивости.
Ответ 11
Не является ошибкой. Это поведение требуется для поддержки нескольких HID для Android.
Таким образом, чтобы показать состояние выбора, вам нужно установить режим выбора списка и фон для поддержки выбранного состояния для "макета списка элементов", например:
android:background="?android:attr/activatedBackgroundIndicator"
FYI: http://android-developers.blogspot.mx/2008/12/touch-mode.html