使用自定义BaseAdapter从ListView中删除项目

8
我正在使用自定义的BaseAdapter来显示ListView上的项目。这些项目只是存储在ArrayList中的字符串。
列表项上有一个删除按钮(大的红色X),我想从ArrayList中删除该项,并通知ListView更新自己。
然而,我尝试过的每个实现都会得到神秘的位置数字,因此例如,点击第2个项目的删除按钮将删除第5个项目。它似乎几乎完全是随机的。
需要注意的一点是,元素可能会重复,但必须保持相同的顺序。例如,我可以两次拥有"Irish"作为第3和第7个元素。
我的代码如下:
private static class ViewHolder {
        TextView lang;
        int position;
}

public View getView(final int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.language_link_row, null);
        holder = new ViewHolder();
        holder.lang = (TextView)convertView.findViewById(R.id.language_link_text);
        holder.position = position;

        final ImageView deleteButton = (ImageView) 
                convertView.findViewById(R.id.language_link_cross_delete);
        deleteButton.setOnClickListener(this);

        convertView.setTag(holder);
        deleteButton.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.lang.setText(mLanguages.get(position));

    return convertView;
}

我后来尝试通过获取标签来找回已删除元素的位置,但它在列表中总是错误的位置。这里给出的位置没有明显的模式,似乎总是随机的。

// The delete button's listener
public void onClick(View v) {

    ViewHolder deleteHolder = (ViewHolder) v.getTag();
    int pos = deleteHolder.position;

    ...
    ...
    ...
}

我很乐意从ArrayList中删除该项并使ListView更新,但我获取的位置是不正确的,所以我无法这样做。
请注意,我最初将deleteButton clickListener放在getView方法中,并使用“position”删除该值,但我遇到了相同的问题。
任何建议都将不胜感激,这真的让我很烦恼。
3个回答

5

每次都需要设置位置。您的实现仅在创建视图时设置位置。但是,当视图被回收时(当convertView不为空时),位置将不会设置为正确的值。

    public View getView(final int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.language_link_row, null);
        holder = new ViewHolder();
        holder.lang = (TextView)convertView.findViewById(R.id.language_link_text);

        final ImageView deleteButton = (ImageView) 
                convertView.findViewById(R.id.language_link_cross_delete);
        deleteButton.setOnClickListener(this);

        convertView.setTag(holder);
        deleteButton.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.lang.setText(mLanguages.get(position));
    holder.position = position;
    return convertView;
}

1
太棒了,谢谢。我简直不敢相信我会在这样一个愚蠢的问题上花费那么长时间。我已将我的通用解决方案作为单独的答案添加,供有兴趣的人参考。 - HXCaine

0

我的最终解决方案是使用Greg的被接受答案和以下方法:

  • 将持有者存储在HashMap中,以项目位置作为键(这在构造函数中初始化为空)

    private HashMap mHolders;

  • 将此用作onClickListner方法:

public void onClick(View v) {
    ViewHolder deleteHolder = (ViewHolder) v.getTag();
    int pos = deleteHolder.position;
    mHolders.remove(pos);

    ViewHolder currentHolder;

    // Shift 'position' of remaining languages 
    // down since 'pos' was deleted
    for(int i=pos+1; i<getCount(); i++){
        currentHolder = mHolders.get(i);
        currentHolder.position = i-1;
    }
    mLanguages.remove(pos);
    notifyDataSetChanged();
}

[请原谅奇怪的格式。代码嵌入未正常工作]


0
你需要实现OnItemClickListener接口,并在onItemClick方法中删除项目,该方法的一个参数是位置。

1
他有一个按钮,因此监听器将不合适。仅当整个列表元素接收到单击事件时,该监听器才起作用。 - Greg Giacovelli

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