ListView项和状态选择背景绘制的怪异的行为怪异、状态、背景、行为

2023-09-05 07:13:43 作者:g_橊誐zαι原dī

我使用的是StateListDrawable为背景时,有一些非常奇怪的ListView的行为。我试着按照答案this的帖子,因为我没有得到state_checked状态下工作,但现在我的ListView是要疯了。

I am having some very strange ListView behavior when using a StateListDrawable as the background. I've tried to follow the answer to this post, as I wasn't getting the state_checked state to work, but now my ListView is going crazy.

当我点击一个项目,它不会立即改变颜色以选择的state_checked项目。点击了一下周围,虽然经过很多的意见,会突然切换到state_checked背景。这看似随意的。

When I click on an item, it doesn't immediately change color to the state_checked item in the selector. After clicking around a bit though, many of the views will suddenly switch to the state_checked background. It's seemingly random.

下面是我的状态选择XML code:

Here is my state selector xml code:

<?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类为我的自定义视图实现辨认的:

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();
    }
}

我周围戳了几个小时试图数字出来,但不幸的是必须承认,以寻求帮助。任何人都可以看到一些错误的code以上,将导致ListView控件来奇怪行为上的项目?我可以发布更多的code,以及,如果需要的话。

I've poked around for a few hours trying to figure it out, but unfortunately must concede to asking for help. Can anyone see something wrong with the code above that would cause the ListView to behave strangely on the items? I can post more code as well, if needed.

推荐答案

在与的ListView工作这是非常重要的时刻牢记的观点是 presentation 的和适配器是的数据模型的。

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

这意味着,所有国家应在适配器(数据模型)的没有的的意见。

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

从我可以告诉你的code,你有正呈现出支票状态的观点,并认为国家是在视图的不是在适配器。即,当用户点击列表中的该项目,所使用的视图,以显示其商品有其内部检查状态改变到切换所显示给用户。

From what I can tell of your code, you have a view that is showing a check state, and that state is in the view not in the adapter. That is, when the user clicks on that item in the list, the view being used to display its item has its internal checked state changed to toggle what is shown to the user.

不过,由于视图不是数据模型,这种状态下你在玩这里是短暂的,而不是真正的适配器项目被点击相关的。

But since the view is not the data model, this state you are playing with here is transient and not actually associated with the adapter item being clicked.

最明显的问题这将导致进入与视图循环。当您通过的ListView ,当项目滚动到了结束,新的出现在底部滚动,用于显示旧项目的意见,重新用于显示新的。这比具有新的项目显示每次充气一个新的项目视图层次更加高效。

The most obvious problem this causes comes in with view recycling. When you scroll through a ListView, when items scroll off the end and new ones appear at the bottom, the views used to display the old items are re-used to display the new ones. This is much more efficient than having to inflate a new item view hierarchy every time a new item is shown.

由于你有你的状态来看,当这种循环发生该国在视图获取随机的一些新项目重新关联。这可以在许多情况下发生,而不是仅仅滚动。

Because you have your state in the view, when this recycling happens that state in the view gets randomly re-associated with some new item. This can happen in many cases, not just scrolling.

解决的办法是把你的支票状态的调节器,并执行 Adapter.getView()来设置视图根据你现在的状态的选中状态在适配器。这样,每当视图被回收(和 getView()称为新的数据行绑定),您将更新其选中状态,以正确地按照新数据是显示。

The solution is to put your check state in the adapter, and implement Adapter.getView() to set the checked state of the view based on the state you now have in the adapter. That way whenever a view is recycled (and getView() called to bind the new data row to it), you will update its checked state to correctly follow the new data it is displaying.