Android API版本8/9中ListView选中项目的颜色设置不正常工作

3

我目前正在使用ListView来展示一些项目。我已经实现了一个操作模式,可以选择多个项目并进行大规模删除,在Android 4.x上运行良好。但是当我尝试使用API版本8或9(Android 2.2.x / 2.3.x)时,选择在内部按预期工作,但行项目的颜色会随机变化。

如果用户选择第一行,内部选择第一行,但第四行被着色。当我点击另一行时,这一行和第一行都被着色。这是一种奇怪的行为,我希望它能像4.x设备上那样正常工作。

长按覆盖以激活操作模式并检查ListView中长按的项目:

@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id) {
    if (actionMode == null) {
        listView.setOnItemClickListener(new CABClickListener());
        actionMode = startActionMode(new ListActionMode());
        // Check item pressed with long click
        listView.setItemChecked(position, true);
        view.setBackgroundColor(checkedColor);
        logger.debug("Item at pos. " + position + ", checked.");
    }
    return true;
}
CABClickListener负责检查/取消ListView项目的选择状态,内部标记它们并更改其背景颜色:
private final class CABClickListener implements AdapterView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
        if (listView.isItemChecked(position)) {
            view.setBackgroundColor(checkedColor);
            logger.debug("Item at pos. " + position + ", checked.");
        } else {
            view.setBackgroundColor(uncheckedColor);
            logger.debug("Item at pos. " + position + ", unchecked.");
        }
    }
}

这些类/方法位于 Activity 内部,listView 在其顶部声明。

更多注意事项:

  • 使用 ActionBarSherlock(它显示了 CAB,但我认为这在这里不重要)和 Roboguice,但我对此没有任何问题。
  • 我一直在使用模拟器进行开发。此外,我无法尝试我的应用程序与 Android 3.x(遇到了问题,模拟器无法启动),因此我不知道问题是否仍然存在于这些版本中。 更新:在 Android 3.0 API 11 中测试,与4.x上一样正常工作。
  • 我调试了代码和两种方法中的 View,但是当我调用 view.setBackgroundColor(checkedColor); 时,另一个 View 被着色了。

有什么建议吗?希望有人能帮忙!

1个回答

3

哇,问题在我的ArrayAdapter实现中,我试图应用视图持有者模式。起初我放弃了这个想法,因为我使用简单的ArrayAdapter进行了相同的测试,但问题仍然存在。

Android API之间的区别在于,在8-10 API中点击项目时,整个列表都会被重新绘制,重用现有视图。因此,当您点击一个项目(视图)时,它会变色,但是立即Android会重新绘制整个列表,重用视图,并使着色的项处于其他位置。在>11 API中单击列表视图项时,不会重新绘制任何内容(是的,在版本之间有很大的性能提升),并且正确的项视图已成功绘制(正确调用view.setBackgroundColor(checkedColor))。

最后,我通过在实体中存储选中状态来解决了这种奇怪的行为。有了这个,当视图需要被回收时,可以恢复选中值,并且可以轻松地对列表项进行着色。

我发布了我的GenericListAdapter<T>.getView()方法及相关内容,供有兴趣的人参考。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ItemViewHolder<T> viewHolder = null;

    if (convertView == null || !(convertView.getTag() instanceof ItemViewHolder<?>)) {
        logger.debug("New view: " + convertView + " at position: " + position);
        LayoutInflater mInflater = LayoutInflater.from(context);
        convertView = mInflater.inflate(resource, null);

        viewHolder = GenericViewHolderFactory.createInstance(clazz);
        viewHolder.setContext(context);
        viewHolder.saveViewContents(convertView);

        convertView.setTag(viewHolder);
    } else {
        logger.debug("Reusing view: " + convertView + ", at position: " + position);
        viewHolder = (ItemViewHolder<T>) convertView.getTag();
    }

    T entity = getItem(position);
    viewHolder.setViewFields(entity, convertView);

    return convertView;
}

以下是刷新回收视图的ViewHolder实现:

public class EventItemViewHolder implements ItemViewHolder<Event> {

...

    @Override
    public void setViewFields(Event event, View convertView) {
        name.setText(event.getName());
        amount.setText(event.getTotalAmount().toString());

        if (event.isChecked()) {
            convertView.setBackgroundColor(checkedColor);
        } else {
            convertView.setBackgroundColor(uncheckedColor);
        }
    }
}

我希望我已经解释清楚了。


1
这是我的类来处理当ActionMode处于活动状态时的listView项OnClick事件:链接 - jelies

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,