Android 尝试从ListView中删除项时,始终会删除第一个项

Android 尝试从ListView中删除项时,始终会删除第一个项,android,listview,Android,Listview,我有一个自定义适配器和一个列表,我可以在单击按钮时动态添加项目。每个列表行都有一个删除按钮(或图像)。这是我的自定义适配器类: package com.ameer.easycooking; import android.content.Context; import android.media.Image; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; i

我有一个自定义适配器和一个列表,我可以在单击按钮时动态添加项目。每个列表行都有一个删除按钮(或图像)。这是我的自定义适配器类:

package com.ameer.easycooking;

import android.content.Context;
import android.media.Image;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

/**
 * Created by ameer on 12/10/2016.
 */
public class IngredientAdapter extends ArrayAdapter<String> {
    private List<String> ingredientList;
    private Context context;

    public IngredientAdapter(List<String> ingredientList, Context context) {
        super(context, R.layout.ingredient_list_item, ingredientList);
        this.ingredientList = ingredientList;
        this.context = context;
    }

    public static class IngredientHolder {
        private TextView name;
        private ImageView remove;

        public IngredientHolder(TextView name, ImageView remove) {
            this.name = name;
            this.remove = remove;
        }

        public TextView getName() {
            return name;
        }

        public ImageView getRemove() {
            return remove;
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;

        IngredientHolder holder;

        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(R.layout.ingredient_list_item, null);

            holder = new IngredientHolder((TextView) v.findViewById(R.id.ingredientName), (ImageView) v.findViewById(R.id.remove));

            holder.getRemove().setTag(position);

            holder.getRemove().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int index = (int) v.getTag();
                    Toast.makeText(context, ingredientList.get(index) + " removed", Toast.LENGTH_SHORT).show();
                    ingredientList.remove(index);
                    notifyDataSetChanged();
                }
            });

            v.setTag(holder);
        } else {
            holder = (IngredientHolder) v.getTag();
        }

        String ingredient = ingredientList.get(position);
        holder.name.setText(ingredient);

        return v;
    }
}
package com.ameer.easycooking;
导入android.content.Context;
导入android.media.Image;
导入android.view.LayoutInflater;
导入android.view.view;
导入android.view.ViewGroup;
导入android.widget.ArrayAdapter;
导入android.widget.ImageView;
导入android.widget.TextView;
导入android.widget.Toast;
导入java.util.List;
/**
*由ameer于2016年10月12日创建。
*/
公共类InCredentAdapter扩展了ArrayAdapter{
私有列表-用户列表;
私人语境;
公共IngredientAdapter(列表ingredientList,上下文){
super(上下文、R.layout.Component\u列表项目、IngCreditList);
this.ingredientList=ingredientList;
this.context=上下文;
}
公共静态类IngreditionHolder{
私有文本视图名称;
私用影像移除;
公共IngredientHolder(文本视图名称,图像视图删除){
this.name=名称;
这个。移除=移除;
}
公共文本视图getName(){
返回名称;
}
公共图像视图getRemove(){
退换货;
}
}
@凌驾
公共视图getView(int位置、视图转换视图、视图组父视图){
视图v=转换视图;
Ingredinterholder持有人;
if(convertView==null){
LayoutFlater充气器=(LayoutFlater)context.getSystemService(context.LAYOUT\u充气器\u服务);
v=充气机。充气(R.layout.Component\u list\u项,空);
holder=new IngredientHolder((TextView)v.findViewById(R.id.ingredientName),(ImageView)v.findViewById(R.id.remove));
holder.getRemove().setTag(位置);
holder.getRemove().setOnClickListener(新视图.OnClickListener()){
@凌驾
公共void onClick(视图v){
int index=(int)v.getTag();
Toast.makeText(context,ingredientList.get(index)+“removed”,Toast.LENGTH_SHORT.show();
IngreditList.remove(索引);
notifyDataSetChanged();
}
});
v、 setTag(支架);
}否则{
holder=(IngredientHolder)v.getTag();
}
字符串成分=IngreditList.get(位置);
holder.name.setText(成分);
返回v;
}
}

我的问题是,无论我添加了多少项或选择删除哪一项,它总是删除ListView中的第一行,而不是单击的那一行。

您只会点击
convertView==null
一次,这就是为什么会出现此问题的原因。您应该设置
holder.getRemove().setTag(位置)if/else
语句之后添加code>

您只会点击一次
convertView==null
,这就是您遇到此问题的原因。您应该设置
holder.getRemove().setTag(位置)if/else
语句之后添加code>

不应在if语句中设置单击侦听器,因为您无法知道何时将使用转换的视图,并且单击的位置可能错误。因此,只需将click listener移出if语句,并删除
holder.getRemove().setTag(position)
语句:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;

    IngredientHolder holder;

    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = inflater.inflate(R.layout.ingredient_list_item, null);
        holder = new IngredientHolder((TextView) v.findViewById(R.id.ingredientName), (ImageView) v.findViewById(R.id.remove));
        v.setTag(holder);
    } else {
        holder = (IngredientHolder) v.getTag();
    }

    String ingredient = ingredientList.get(position);
    holder.name.setText(ingredient);

    holder.getRemove().setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int index = (int) v.getTag();
            Toast.makeText(context, ingredientList.get(index) + " removed", Toast.LENGTH_SHORT).show();
            ingredientList.remove(index);
            notifyDataSetChanged();
        }
    });

    return v;
}

编辑:或者正如Blackbelt所说,您只需移动
holder.getRemove().setTag(位置)语句脱离if块。

您不应该在if语句中设置单击侦听器,因为您无法知道何时将使用转换的视图,并且单击的位置可能错误。因此,只需将click listener移出if语句,并删除
holder.getRemove().setTag(position)
语句:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;

    IngredientHolder holder;

    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = inflater.inflate(R.layout.ingredient_list_item, null);
        holder = new IngredientHolder((TextView) v.findViewById(R.id.ingredientName), (ImageView) v.findViewById(R.id.remove));
        v.setTag(holder);
    } else {
        holder = (IngredientHolder) v.getTag();
    }

    String ingredient = ingredientList.get(position);
    holder.name.setText(ingredient);

    holder.getRemove().setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int index = (int) v.getTag();
            Toast.makeText(context, ingredientList.get(index) + " removed", Toast.LENGTH_SHORT).show();
            ingredientList.remove(index);
            notifyDataSetChanged();
        }
    });

    return v;
}

编辑:或者正如Blackbelt所说,您只需移动
holder.getRemove().setTag(位置)语句脱离if块。

使在getView()中传递的位置成为final的更好方法 公共视图getView(最终整数位置、视图转换视图、视图组父视图)
然后在click listener中使用该位置。

使在getView()中传递的位置成为最终位置的更好方法 公共视图getView(最终整数位置、视图转换视图、视图组父视图)
然后在click listener中使用该位置。

否单击OnClick listener。仅
holder.getRemove().setTag(位置)是的,好吧,你说的是真的。@Carnal我是这样做的,它解决了我的问题。不,是我的听众。仅
holder.getRemove().setTag(位置)是的,好的,你说的是真的。@Carnal我这样做,解决了我的问题。move
holder.getRemove().setTag(position)在if/else之后logic@Blackbelt谢谢,现在工作正常了。:)移动
holder.getRemove().setTag(位置)在if/else之后logic@Blackbelt谢谢,现在工作正常了。:)是的,我照布莱克贝尔说的做了,现在开始工作了。不过我有个问题。如果我选择按照你的建议去做,那么
intindex=(int)v.getTag()将不再工作,因为我不会为它设置标记,不是吗?是的,但是如果你在if块外定义了click侦听器,那么你就不需要设置标记。是的,我按照Blackbelt说的做了,现在它工作了。不过我有个问题。如果我选择按照你的建议去做,那么
intindex=(int)v.getTag()将不再工作,因为我不会为它设置标记,否?是的,但是如果您在if块外定义了click侦听器,则不需要设置标记。