Strange behavior of a ListView item and state selector state

I get a very strange ListView behavior when using StateListDrawable as the background. I tried to answer this one as I did not get state_checked state, but now my ListView is going crazy.

When I click on an element, it does not immediately change color to the state_checked element in the selector. After clicking a little, many of the species will suddenly switch to state_checked background. It seems random.

Here is my state selector 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> 

And here is my .java class for my custom view implementing 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(); } } 

I tried to understand for several hours, but, unfortunately, I have to agree to a request for help. Can someone see something wrong with the code above, which will cause the ListView to behave strangely on the elements? If necessary, I can send another code.

+6
source share
3 answers

When working with a ListView it is very important to always keep in mind that the views are a presentation, and the adapter is a data model.

This means that all your state should be in the adapter (data model), and not in the views.

From what I can say about your code, you have a view showing the status of the check, and this state is in the view not in the adapter. That is, when a user clicks on this item in the list, the view used to display its item has its internal validation state, changed to switch what is shown to the user.

But since the view is not a data model, this state in which you play here is transient and is not actually associated with clicking on an adapter element.

The most obvious problem caused by this problem is related to the processing of the species. When you scroll through a ListView , when items scroll to the end and new ones appear below, views used to display old items are reused to display new ones. This is much more efficient than inflating a new hierarchy of item positions each time a new item is displayed.

Since you have your state in the view, when this recirculation occurs, the state in the view becomes randomly associated with some new element. This can happen in many cases, not just scrolling.

The solution is to put your validation state in the adapter and implement Adapter.getView() to set the verified state of the view based on the state you currently have in the adapter. Thus, whenever the view is processed (and getView() is called to bind a new row of data to it), you will update its checked state to correctly follow the new displayed data.

+21
source

I do not think the problem comes from the code above. I used to have this problem, and this is due to the processing of the views in the list. This may be for you if your list continues on the screen. If so, a good way to fix this is to keep the states of the items in the list so that you can track them and base your states outside the list that you created. Check out this and this for more information on recycling views.

+3
source

When you do something similar with a rather complicated set of ListViews, I added an additional list for the adapter and added the position of the clicked elements to it. getView (...) then inflates / redesigns the view and just before completing checking the state of the element and the state of the internal adapter to decide which background to apply.

I also customize the state list file to make the background transparent when clicked so that the selector is visible, it works with pleasure.

0
source

Source: https://habr.com/ru/post/892358/


All Articles