3

我目前正在使用 ListView 来显示一种项目。我已经实现了一个动作模式来选择多个项目并大量删除,这在 android 4.x 中运行良好。但是当我尝试使用 API 版本 8 或 9 (android 2.2.x/2.3.x) 时,选择在内部按预期工作,但行项目的颜色是随机的。

如果用户选择第一行,则在内部选择第一行,但第 4 行是彩色的。当我单击另一行时,这一行和第一行是彩色的。这是一种奇怪的行为,我希望在 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两种方法中的 s 都可以,但是当我调用 时 view.setBackgroundColor(checkedColor);,另一个View是彩色的。

有什么建议吗?希望任何人都可以提供帮助!

4

1 回答 1

3

哇,问题出在我自己的实现中ArrayAdapter,我尝试应用视图持有者模式。我最初放弃了这个,因为我用一个简单的方法测试了它ArrayAdapter,问题仍然存在。

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

最后,我解决了这种奇怪的行为,将检查状态存储在实体中。这样,当必须回收视图时,可以恢复检查值并且可以毫无问题地为列表项着色。

我发布了我的 GenericListAdapter.getView() 方法和相关的任何感兴趣的人。

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

我希望我已经很好地解释了自己。

于 2012-07-27T18:44:17.607 回答