ListView项和状态选择器背景drawable的奇怪行为

Joh*_*hey 6 android listview drawable

使用StateListDrawable作为背景时,我有一些非常奇怪的ListView行为.我试图按照这篇文章的答案,因为我没有让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>
Run Code Online (Sandbox Code Playgroud)

这是我的自定义视图实现可检查的.java类:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我试着弄清楚了几个小时,但不幸的是必须让步以寻求帮助.任何人都可以看到上面的代码有问题会导致ListView在项目上表现奇怪吗?如果需要,我也可以发布更多代码.

hac*_*bod 21

使用ListView它时,始终牢记视图是演示文稿,适配器是数据模型是非常重要的.

这意味着您的所有状态都应该在适配器(数据模型)中,而不是在视图中.

从我所知道的代码,你有一个显示检查状态的视图,并且该状态在视图中不在适配器中.也就是说,当用户点击列表中的该项时,用于显示其项目的视图的内部检查状态已更改为切换显示给用户的内容.

但由于视图不是数据模型,因此您在此处使用的状态是瞬态的,并且实际上与所单击的适配器项目无关.

这引起的最明显的问题是视图回收.滚动浏览a时ListView,当项目滚动到底部并且新项目显示在底部时,用于显示旧项目的视图将重新用于显示新项目.这比每次显示新项目时必须为新的项目视图层次结构充气更有效.

因为您在视图中拥有自己的状态,所以当此回收发生时,视图中的状态会随机重新关联到某个新项目.在许多情况下可能会发生这种情况,而不仅仅是滚动.

解决方案是将您的检查状态放在适配器中,并Adapter.getView()根据您现在在适配器中的状态实现设置检查的视图状态.这样,只要视图被回收(并getView()调用以将新数据行绑定到该视图),您将更新其已检查状态以正确地跟踪它正在显示的新数据.