【问题标题】:setSelected() works buggy with ListViewsetSelected() 与 ListView 一起工作
【发布时间】:2015-02-04 18:31:58
【问题描述】:

我只是想让 ListView 的点击项目来改变背景。但在我看来,这实际上是不可能的。有很多帖子都有这样做的例子,但没有一个是可靠的。据我了解 - 它在某种程度上与“回收”有关。

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

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

  1. 我单击了一个 ListView 项目。它将背景更改为“选定的颜色”。
  2. 我正在等待片刻。
  3. 活动内容正在根据服务响应发生变化。 ListView 内部会出现一个滚动条。项目背景更改为“默认颜色”(取消选择项目)。

单击不会导致滚动条出现的项目效果很好 - 处理服务响应后选定的项目不会被取消选择。

尝试在适配器的 getView() 中调用 setSelected() 不会影响该错误。项目仍在取消选择中。我尝试在 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。

【问题讨论】:

    标签: android listview recycle


    【解决方案1】:

    对于 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;很有趣。

    【讨论】:

    • 不幸的是我使用 API-7,它没有 state_activated。
    • 那么我认为你是正确的,你的方式是唯一的方式
    【解决方案2】:

    我对颜色有点困惑。在修复了一些愚蠢的错误后,我的选择通过直接从 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;
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-21
      相关资源
      最近更新 更多