Android自定义适配器Listview 1选择导致多选

Android custom adapter Listview 1 selection causes multiple selections

我有一个带有自定义适配器的列表视图,里面有一个切换按钮、一个微调器和一些其他视图。

此列表视图显示的项目多于 1 个屏幕通常可以容纳的项目,这导致了一个我不明白的奇怪问题。

例如: 当我按下列表中第一项的切换按钮时,背景会改变颜色。如果我然后向下滚动到“第二个屏幕”(第 10-18 项),我注意到第 11 个项目也已 "toggled" 因为背景也发生了变化。如果我再向下滚动到第 20 个项目也被选中。

我的适配器是这样的:

public class ArticlesListAdapter extends ArrayAdapter<Line> {

private List<Line> lineList;
private Context context;

public ArticlesListAdapter(Context context, int textViewResourceId,
        List<Line> objects) {
    super(context, textViewResourceId, objects);
    this.lineList = objects;
    this.context = context;
}

public int getCount() {
    return lineList.size();
}

public Line getItem(int position) {
    return lineList.get(position);
}

public long getItemId(int position) {
    return position;
}

public List<Line> GetAllLines() {
    return lineList;

}

@SuppressLint("InflateParams")
public View getView(int position, View convertView, ViewGroup parent) {

    Viewholder viewholder;

    if (convertView == null) {
        viewholder = new Viewholder();
        convertView = LayoutInflater.from(context).inflate(
                R.layout.articles_list_row, null);

        viewholder.articleName = (TextView) convertView
                .findViewById(R.id.textArticleName);
        viewholder.articleAmount = (EditText) convertView
                .findViewById(R.id.textArticleAmount);
        viewholder.articleButton = (ToggleButton) convertView
                .findViewById(R.id.toggleArticleReturn);
        viewholder.articleStock = (Spinner) convertView
                .findViewById(R.id.spinStockWarehouse);

        convertView.setTag(viewholder);
    } else {
        viewholder = (Viewholder) convertView.getTag();
    }

    viewholder.articleButton.setTag(position);

    if (lineList.get(position).getLineCode().length() > 0) {
        viewholder.articleButton.setOnClickListener(RetourArticleListener);
        viewholder.articleButton.setOnLongClickListener(RetourCertainAmountArticleListener);
    } else {
        viewholder.articleButton.setText("Delete");
        viewholder.articleButton.setOnClickListener(DeleteArticleListener);
    }

    String articleNameString = lineList.get(position)
            .getLineArticleDescription();
    if (articleNameString.length() > 30) {
        articleNameString.substring(0, 30);
    }
    viewholder.articleName.setText(articleNameString);
    viewholder.articleName.setTextSize(12);

    viewholder.articleAmount.setTag(position);
    viewholder.articleAmount.setTextSize(12);
    viewholder.articleAmount.setText(lineList.get(position)
            .getLineArticleAmount().toString());

    if (lineList.get(position).isLineArticleIsOriginal()) {
        viewholder.articleStock.setEnabled(false);
    }
    viewholder.articleStock.setSelection(Integer.parseInt(lineList
            .get(position).getLineArticleStock().toString()) - 1);
    viewholder.articleStock.setTag(position);
    viewholder.articleStock
            .setOnItemSelectedListener(new OnItemSelectedListener() {

                @Override
                public void onItemSelected(AdapterView<?> adapterView,
                        View view, int position, long id) {
                    final int listPosition = (Integer) adapterView.getTag();
                    lineList.get(listPosition).setLineArticleStock(
                            String.valueOf(position + 1));
                }

                @Override
                public void onNothingSelected(AdapterView<?> adapter) {
                }
            });

    // we need to update adapter once we finish with editing
    viewholder.articleAmount
            .setOnFocusChangeListener(new OnFocusChangeListener() {
                public void onFocusChange(View v, boolean hasFocus) {
                    if (!hasFocus) {
                        final int position = (Integer) v.getTag();
                        final EditText articleAmount = (EditText) v;
                        lineList.get(position).setLineArticleAmount(
                                Double.parseDouble(articleAmount.getText()
                                        .toString().replace(",", ".")));
                    }
                }
            });

    return convertView;
}

private OnClickListener RetourArticleListener = new OnClickListener() {

    @Override
    public void onClick(View v) {
        boolean on = ((ToggleButton) v).isChecked();
        int position = (Integer) v.getTag();
        RelativeLayout rl = (RelativeLayout) v.getParent();
        if (on) {
            // Article returned
            rl.setBackgroundColor(Color.RED);
            lineList.get(position).setLineArticleReturned(true);
        } else {
            // Article used
            rl.setBackgroundColor(Color.WHITE);
            lineList.get(position).setLineArticleReturned(false);
        }

    }
};
}

这是 listView 回收机制问题的明显案例。例如,您应该阅读 this SO Q&A

正如 Alex.F 所指出的,问题在于 ListView 的回收行为。解决方案非常简单:

您的订单项已有一个与颜色状态相对应的布尔值,我们将使用它。

在您的 RetourArticleListener 中,将 if-else 语句更改为:

if (on) {
     // Article returned
     lineList.get(position).setLineArticleReturned(true);
     notifyDatasetChanged();
} else {
     // Article used
     lineList.get(position).setLineArticleReturned(false);
     notifyDatasetChanged();
}

notifyDatasetChanged 方法将确保您的 getView() 方法被调用。

在您的 getView() 方法中,检查 "LineArticleReturned" 的值并相应地更改背景颜色。将它添加到 getView 方法末尾的某处,这样您就可以确定所有必需的变量都已初始化。我假设您有一个名为 getLineArticleReturned() 的方法,其中 returns LineArticleReturned 的布尔值在您的行中 class.

 if(lineList.get(position).getLineArticleReturned()==true){
     RelativeLayout rl = (RelativeLayout)          
     convertView.findViewById(R.id.name_of_your_relative_layout_here);
     rl.setBackgroundColor(Color.RED);

 }else{
     rl.setBackgroundColor(Color.WHITE);
 }