Странное поведение элемента списка ListView и state selector

У меня возникает очень странное поведение ListView при использовании StateListDrawable в качестве фона. Я попытался выполнить ответ на этот пост, поскольку я не получил состояние state_checked, но теперь мой ListView сходит с ума.

Когда я нажимаю на элемент, он не сразу меняет цвет на элемент state_checked в селекторе. Если немного щелкнуть, многие из видов внезапно переключится на фон state_checked. Это, по-видимому, случайное.

Вот мой код выбора xml:

<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" > <shape> <gradient android:startColor="@color/grey" android:endColor="@color/darkgrey" android:angle="270" /> <stroke android:width="0dp" android:color="@color/grey05" /> <corners android:radius="0dp" /> <padding android:left="10sp" android:top="10sp" android:right="10sp" android:bottom="10sp" /> </shape> </item> <item android:state_focused="true" > <shape> <gradient android:endColor="@color/orange4" android:startColor="@color/orange5" android:angle="270" /> <stroke android:width="0dp" android:color="@color/grey05" /> <corners android:radius="0dp" /> <padding android:left="10sp" android:top="10sp" android:right="10sp" android:bottom="10sp" /> </shape> </item> <item android:state_checked="true"> <shape> <gradient android:endColor="@color/brown2" android:startColor="@color/brown1" android:angle="270" /> <stroke android:width="0dp" android:color="@color/grey05" /> <corners android:radius="0dp" /> <padding android:left="10sp" android:top="10sp" android:right="10sp" android:bottom="10sp" /> </shape> </item> <item android:state_selected="true"> <shape> <gradient android:endColor="@color/brown2" android:startColor="@color/brown1" android:angle="270" /> <stroke android:width="0dp" android:color="@color/grey05" /> <corners android:radius="0dp" /> <padding android:left="10sp" android:top="10sp" android:right="10sp" android:bottom="10sp" /> </shape> </item> <item> <shape> <gradient android:startColor="@color/white" android:endColor="@color/white2" android:angle="270" /> <stroke android:width="0dp" android:color="@color/grey05" /> <corners android:radius="0dp" /> <padding android:left="10sp" android:top="10sp" android:right="10sp" android:bottom="10sp" /> </shape> </item> </selector> 

И вот мой класс .java для моего пользовательского представления, реализующего checkable:

 public class Entry extends LinearLayout implements Checkable { public Entry(Context context) { super(context, null); // Inflate this view LayoutInflater temp = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); temp.inflate(R.layout.entry, this, true); initViews(); } private static final int[] CheckedStateSet = { android.R.attr.state_checked }; private void initViews() { this.setBackgroundResource(R.drawable.listview_row); } public boolean isChecked() { return _checked; } public void toggle() { _checked = !_checked; } public void setChecked(boolean checked) { _checked = checked; } @Override protected int[] onCreateDrawableState(int extraSpace) { final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); if (isChecked()) { mergeDrawableStates(drawableState, CheckedStateSet); } return drawableState; } @Override public boolean performClick() { toggle(); return super.performClick(); } } 

Я несколько часов пытался понять, но, к сожалению, должен согласиться на просьбу о помощи. Может ли кто-нибудь увидеть что-то не так с кодом выше, что приведет к тому, что ListView будет вести себя странно по элементам? При необходимости я могу отправить еще код.

Solutions Collecting From Web of "Странное поведение элемента списка ListView и state selector"

При работе с ListView очень важно всегда помнить, что представления представляют собой презентацию, а адаптер – модель данных .

Это означает, что все ваше состояние должно быть в адаптере (модели данных), а не в представлениях.

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

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

Наиболее очевидная проблема, связанная с этой проблемой, связана с переработкой вида. Когда вы просматриваете ListView , когда элементы прокручиваются с конца, а новые появляются внизу, виды, используемые для отображения старых элементов, повторно используются для отображения новых. Это намного эффективнее, чем необходимость накачивать новую иерархию представлений элементов каждый раз, когда отображается новый элемент.

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

Решение состоит в том, чтобы поместить ваше состояние проверки в адаптер и реализовать Adapter.getView() чтобы установить проверенное состояние представления на основе состояния, которое вы сейчас имеете в адаптере. Таким образом, всякий раз, когда представление перерабатывается (и getView() для привязки к нему новой строки данных), вы обновите его проверенное состояние, чтобы правильно следить за новыми данными, которые он отображает.

Я не думаю, что проблема исходит из вышеприведенного кода. Раньше у меня была эта проблема, и это связано с переработкой взглядов в списке. Это может быть для вас, если ваш список продолжается с экрана. Если это так, хороший способ исправить это – сохранить состояния элементов в списке, чтобы вы могли отслеживать их и основывать свои состояния вне списка, который вы создали. Взгляните на это и на это, чтобы получить дополнительную информацию об утилизации просмотров.

Когда вы делаете что-то подобное с довольно сложным набором ListViews, я добавил дополнительный список к адаптеру и добавил к нему позицию щелкнувших элементов. GetView (…) затем раздувает / перерабатывает представление и перед тем, как он завершит проверку состояния элемента и состояния внутреннего адаптера, чтобы решить, какой фон применить.

Я также настраиваю xml-файл списка состояний, чтобы сделать фоновый прозрачный, когда он нажат, поэтому селектор виден, он работает.