【问题标题】:ListView adapter behaves strangelyListView 适配器行为异常
【发布时间】:2023-03-28 00:29:01
【问题描述】:

ListView 适配器做了一些奇怪的事情。方法getChecked()(如下所示的适配器代码)没有返回我期望的值。好像他迟到了一步。

为了理解,我将解释:我使用的是自定义ListView,每个项目都包含一个CheckBox(和其他Views)。我想在按下按钮时显示选中元素的位置。这使得方法getChecked()。 但是会发生以下情况:我检查第 2 和第 4 个列表项并单击按钮,结果 - [],然后我检查第 5 项,结果 - [2, 4],然后我清除所有 CheckBoxes,结果 [2, 4, 5] 当我再次单击该按钮时,我收到 - []。结果晚了一步。

public class ContactAdapter extends BaseAdapter {

private LayoutInflater inflater;
private ArrayList<Contact> contacts;

private boolean isCheckBoxVisible;
private View view;

private int[] colors = {Color.BLACK, Color.BLUE, Color.RED, Color.GRAY, Color.GREEN};
private int currentMaleColor;
private int currentFemaleColor;

public ContactAdapter(Context context, ArrayList<Contact> contacts) {
    this.contacts = contacts;
    inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    isCheckBoxVisible = false;
    setColors();
}

@Override
public int getCount() {
    return contacts.size();
}

@Override
public Object getItem(int position) {
    return contacts.get(position);
}

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

private Contact getContact(int position) {
    return (Contact) getItem(position);
}

public void setCheckBoxVisibility(boolean isVisible) {
    isCheckBoxVisible = isVisible;
    notifyDataSetChanged();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    view = convertView;
    if (view == null) {
        view = inflater.inflate(R.layout.contact_item, parent, false);
    }

    CheckBox cb = (CheckBox) view.findViewById(R.id.lv_box);
    if (isCheckBoxVisible) {
        cb.setVisibility(View.VISIBLE);
    } else {
        cb.setVisibility(View.INVISIBLE);
    }

    Contact c = getContact(position);
    ((TextView) view.findViewById(R.id.lv_name)).setText(c.getName() + " " + c.getSurname());
    ((ImageView) view.findViewById(R.id.lv_img)).setImageBitmap(c.getPhoto());

    if (c.getSex().equals("Man")) {
        view.setBackgroundColor(currentMaleColor);
    } else {
        view.setBackgroundColor(currentFemaleColor);
    }

    boolean isCheck = ((CheckBox) view.findViewById(R.id.lv_box)).isChecked();
    contacts.get(position).setChecked(isCheck);
    return view;
}

public ArrayList<Integer> getChecked() {
    notifyDataSetChanged();
    ArrayList<Integer> IDs = new ArrayList<Integer>();
    for (Contact c : contacts) {
        if (c.isChecked()) IDs.add(c.getID());
    }
    return IDs;
}

private void setColors() {
    int colorM = Integer.parseInt(MainActivity.sp.getString("lp_colorM", "0"));
    int colorW = Integer.parseInt(MainActivity.sp.getString("lp_colorW", "0"));

    currentMaleColor = colors[colorM];
    currentFemaleColor = colors[colorW];
}

}

在我的活动中,我使用我的适配器,如下所示:

@Override
protected void onResume() {
    super.onResume();
    adapter = new ContactAdapter(getApplicationContext(), contacts);
    list.setAdapter(adapter);
}

我的按钮代码:

ArrayList<Integer> al = adapter.getChecked();
Toast.makeText(this, al.toString(), Toast.LENGTH_LONG).show();

您对此有何看法?我会很高兴得到任何帮助。

【问题讨论】:

  • contacts.get(position).setChecked(isCheck); 如果联系人仅在刷新视图时更新状态,而不是在单击视图时更新状态。使用 CB 上的 checkedchangedlistener 立即检测更改。
  • 好主意,njzk2。我会努力做到的。但是我有一个问题——为什么现在方法 getChecked() 给出了迟到的结果?我认为如果适配器没有更新,这个方法现在根本不应该工作。
  • 因为 getChecked 返回对setChecked 的调用结果,由于它仅根据 convertView 的状态进行更新,因此延迟。 (如果你有足够的项目可以滚动,它会给出更奇怪的结果。)
  • 嗯......我会在检查它的工作原理时回答你;)
  • 非常感谢!它像魅力一样工作!

标签: android listview android-listview adapter listview-adapter


【解决方案1】:

如果 convertView == null 则尝试获取视图状态

 if (convertView == null) {
            holder = new Holder();
            convertView = mInflator.inflate(R.layout.row_viewproduct, null);
            convertView.setTag(holder);
        } else {
            holder = (Holder) convertView.getTag();
        }

// 设置要从持有者查看的数据

【讨论】:

  • 谢谢你的回答,但是什么是类 - Holder?什么意思?
  • view = convertView; if (view == null) { view = inflater.inflate(R.layout.contact_item, parent, false); } else { view = (View) convertView.getTag(); }
【解决方案2】:

这不是答案,但想说你可以在下面使用

private void setColors() {
        int colorM = Integer.parseInt(MainActivity.sp.getString("lp_colorM", "0"));
        int colorW = Integer.parseInt(MainActivity.sp.getString("lp_colorW", "0"));

        if(colorM < 5){
            currentMaleColor = colors[colorM];
        }

        if(colorW < 5){
            currentFemaleColor = colors[colorM];
        }  
    }

要回答您的问题,请查看视图持有者模式 http://ricston.com/blog/optimising-listview-viewholder-pattern/

【讨论】:

  • 凯文克莱恩,非常感谢您的评论。由于某种原因我之前没有注意它,但现在更正了我的代码。
  • 很高兴,你可以使用 colorM
【解决方案3】:

在njzk2的建议下,我改了:

boolean isCheck = ((CheckBox) view.findViewById(R.id.lv_box)).isChecked();
contacts.get(position).setChecked(isCheck);

此时:

CheckBox checkBox = (CheckBox) view.findViewById(R.id.lv_box);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        contacts.get(position).setChecked(isChecked);
    }
});

现在可以了:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    • 2019-11-19
    • 1970-01-01
    • 2016-11-25
    • 1970-01-01
    相关资源
    最近更新 更多