setSelected()与ListView一起工作

时间:2014-12-06 19:09:52

标签: android listview recycle

我试图让ListView的点击项目改变背景。但在我看来,实际上并不可能。有很多帖子都有这样做的例子,但没有一个可靠地运作。据我了解 - 它以某种方式与回收"。

有关

我在适配器的OnItemClickListener中调用view.setSelected(),它根据我的设置很好地将另一个背景应用于所选项目。但是,当我选择导致ListView缺少空间的项目(不确切的重要性)并且在ListView内部出现(或消失)scollbar时,android会忘记我的选择并应用默认样式。旋转屏幕时会发生同样的错误 - 该项目取消选择。所以我认为"取消选择"在调用适配器的getView()时发生。

有趣的是,我的onClick事件导致向后台服务发送json请求并接收和解码json响应,因此项目点击和活动内容更改之间需要一些时间。这是它的外观:

  1. 我单击一个ListView项。它将背景更改为"选择颜色"。
  2. 很少有人在等我。
  3. 活动内容根据服务响应而变化。 ListView中会出现一个滚动条。项目背景更改为"默认颜色" (项目被取消选择)。
  4. 点击不会导致滚动条显示的项目效果很好 - 在处理服务的响应后,所选项目不会被取消选择。

    尝试在适配器的getView()内调用setSelected()不会影响bug。物品仍然被取消选择。我尝试在getView()中手动设置项目的背景 - 它变得更有趣:导致滚动条外观的项目开始正常工作,但不会导致滚动条出现的项目(实际上它意味着他们不会导致getView()调用停止工作!

    所有代码都非常复杂,所以我只会发布一些重要的片段。这是我的OnItemClickListener:

    private AdapterView.OnItemClickListener onCategoryClickListener =
            new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, final View view, final int position,
                long id) {
            categoriesAdapter.setSelectedPosition(position);
            view.setSelected(true);
            // More code here
        }
    };
    

    这是我的适配器代码的一部分:

    private int selectedPosition;
    private boolean selectable = true;
    
    public void setSelectedPosition(int position) {
        this.selectedPosition = position;
    }
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TextView label = (TextView) View.inflate(context, textViewResourceId, null);
        label.setText(getName(values.get(position)));
        if(selectable) {
            label.setBackgroundResource(R.drawable.list_selector);
            if(position == selectedPosition) {
                label.setSelected(true);  // This does not work. Why?
                label.setBackgroundColor(  // This gives strange results
                    context.getResources().getColor(R.color.list_item_selected_color));
            } else {
                // Similar code here, but for deselecting items.
            }
        }
        return label;
    }
    

    这是我的选择器:

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item
            android:drawable="@color/list_item_default_color"
            android:state_selected="false" />
        <item
            android:drawable="@color/list_item_selected_color"
            android:state_selected="true"/>
    </selector>
    

    我搜索了很多如何使它工作,但没有任何帮助。以下是我尝试过的一些事情:

    • 在view.post()
    • 中运行view.setSelected()
    • 运行list.setSelection() - 这个方法是什么用的?它什么都没做!
    • 初始化TextView更准确,检查convertView是否为null。产生坏的,非常糟糕的结果 - 导致ListView项目随机播放(对其选择状态没有任何影响)。
    • 没有使用ViewHolder,因为我没有Item的复杂布局,我只有一个简单的TextView。

2 个答案:

答案 0 :(得分:10)

对于API 11 +:

1)将列表视图设置为单选:

<ListView
        android:choiceMode="singleChoice" />

2)将项目布局的根元素的背景设置为选择器:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@drawable/selector">

3)将android:state_selected更改为 android:state_activated

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/list_item_selected_color"
        android:state_activated="true"/>
    <item android:drawable="@color/list_item_default_color"/>
</selector>

4)使用listView.setItemChecked(index, true);

突出显示项目

注意: 为了明确视图的状态,特别是 state_activated ,您可以查看this post;这很有趣。

答案 1 :(得分:0)

我对颜色感到困惑。在修复了一些愚蠢的错误之后,通过直接从OnItemClickListener和getView设置背景颜色,我的选择可靠地工作:

修复了OnItemClickListener:

public void onItemClick(AdapterView<?> parent, final View view, final int position,
        long id) {
    categoriesAdapter.setSelectedPosition(position);
    for (int j = 0; j < parent.getChildCount(); j++) {
        parent.getChildAt(j).setSelected(false);
        parent.getChildAt(j).setBackgroundColor(getContext().getResources().getColor(
            R.color.list_item_default_color));
    }
    view.setBackgroundColor(getContext().getResources().getColor(
        R.color.list_item_selected_color));

    // More code here
}

固定适配器:

private Integer selectedPosition;

public void setSelectedPosition(int position) {
    this.selectedPosition = position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    TextView label = (TextView) View.inflate(context, textViewResourceId, null);
    label.setText(getName(values.get(position)));
    if(selectedPosition != null) {
        if(position == selectedPosition) {
            label.setBackgroundColor(context.getResources()
                .getColor(R.color.list_item_selected_color));
        } else {
            label.setBackgroundColor(context.getResources()
                .getColor(R.color.list_item_default_color));
        }
    }
    return label;
}

因此,使用<selector>执行此操作的方法不起作用,因为android无法可靠地切换窗口小部件状态。是正确还是有人“<selector>方式”工作?