View Holder 模式不起作用
View Holder pattern not working
我实现了一个自定义列表视图,其中有两个文本视图和复选框。这些被封装到一个线性布局中,点击我 check/uncheck 复选框。我面临的问题是,当我单击线性布局时,它会检查复选框,但它也会检查固定模式上的其他复选框,即每 7-8 行。我读了很多关于它的问题,发现实现视图持有者可以解决问题,但这对我也不起作用。以下是我的代码:
自定义列表适配器:
public class ContactsListAdapter extends BaseAdapter{
private Context context;
private List<ContactInfo> contacts;
private List<ContactInfo> selectedContacts;
public ContactsListAdapter(Context context, List<ContactInfo> contacts) {
this.context = context;
this.contacts = contacts;
selectedContacts = new ArrayList<ContactInfo>();
}
public List<ContactInfo> getSelectedContacts() {
return selectedContacts;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return contacts.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return contacts.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return Long.parseLong(contacts.get(position).id);
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final ViewHolder holder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.contacts_list_row_item, null);
holder = new ViewHolder();
holder.view = (LinearLayout) convertView.findViewById(R.id.llContactRow);
holder.name = (TextView) convertView.findViewById(R.id.tvContactName);
holder.number = (TextView) convertView.findViewById(R.id.tvContactNumber);
holder.checkbox = (CheckBox) convertView.findViewById(R.id.cbMultipleSelect);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.name.setText(contacts.get(position).name);
holder.number.setText(contacts.get(position).number);
holder.view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ContactInfo contact = new ContactInfo();
contact.id = contacts.get(position).id;
contact.name = contacts.get(position).name;
contact.number = contacts.get(position).number;
holder.checkbox.setChecked(!holder.checkbox.isChecked());
if(holder.checkbox.isChecked()) {
selectedContacts.add(contact);
} else {
selectedContacts.remove(contact);
}
}
});
return convertView;
}
private static class ViewHolder {
LinearLayout view;
CheckBox checkbox;
TextView name;
TextView number;
}
}
我做错了什么?请帮忙。
编辑:
完成@vinitius 要求我做的事情后,问题已解决,但当我滚动列表时,支票消失了。这是我的新 getView()
:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final ViewHolder holder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.contacts_list_row_item, null);
holder = new ViewHolder();
holder.view = (LinearLayout) convertView.findViewById(R.id.llContactRow);
holder.name = (TextView) convertView.findViewById(R.id.tvContactName);
holder.number = (TextView) convertView.findViewById(R.id.tvContactNumber);
holder.checkbox = (CheckBox) convertView.findViewById(R.id.cbMultipleSelect);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.name.setText(contacts.get(position).name);
holder.number.setText(contacts.get(position).number);
holder.checkbox.setChecked(selectedContacts.contains(contacts.get(position)));
holder.view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ContactInfo contact = new ContactInfo();
contact.id = contacts.get(position).id;
contact.name = contacts.get(position).name;
contact.number = contacts.get(position).number;
holder.checkbox.setChecked(!holder.checkbox.isChecked());
if(holder.checkbox.isChecked()) {
selectedContacts.add(contact);
} else {
selectedContacts.remove(contact);
}
}
});
return convertView;
}
您的问题是您需要将 holder.checkbox.setChecked() 设置为以下行下方的值:
holder.number.setText(contacts.get(position).number);
当前您在检查它时更改它的值,但您需要在调用 getview 方法时设置该值,否则它将保留之前的任何值。
如果您的联系人信息中有一个 'selected' 值而不是管理一个新列表,那可能是最好的。这样你就可以做类似的事情:
holder.checkbox.setChecked(contacts.get(position).isSelected);
您没有在 getView()
中显示您的内容。执行以下操作:
@Override
public void onClick(View v) {
//remove the other stuff. You don't want to create new instances here, otherwise you won't be able to remove them later
holder.checkbox.setChecked(!holder.checkbox.isChecked());
if(holder.checkbox.isChecked()) {
selectedContacts.add(contact.get(position));
} else {
selectedContacts.remove(contact.get(position));
}
}
并在为 LinearLayout
设置 OnClickListener
之前执行此操作:
holder.checkbox.setChecked(selectedContacts.contains(contacts.get(position)));
如果您希望在点击 CheckBox
时有相同的行为,只需添加到您的 CheckBox
xml:
android:clickable="false"
所以linearLayout
可以拦截它
我实现了一个自定义列表视图,其中有两个文本视图和复选框。这些被封装到一个线性布局中,点击我 check/uncheck 复选框。我面临的问题是,当我单击线性布局时,它会检查复选框,但它也会检查固定模式上的其他复选框,即每 7-8 行。我读了很多关于它的问题,发现实现视图持有者可以解决问题,但这对我也不起作用。以下是我的代码:
自定义列表适配器:
public class ContactsListAdapter extends BaseAdapter{
private Context context;
private List<ContactInfo> contacts;
private List<ContactInfo> selectedContacts;
public ContactsListAdapter(Context context, List<ContactInfo> contacts) {
this.context = context;
this.contacts = contacts;
selectedContacts = new ArrayList<ContactInfo>();
}
public List<ContactInfo> getSelectedContacts() {
return selectedContacts;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return contacts.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return contacts.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return Long.parseLong(contacts.get(position).id);
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final ViewHolder holder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.contacts_list_row_item, null);
holder = new ViewHolder();
holder.view = (LinearLayout) convertView.findViewById(R.id.llContactRow);
holder.name = (TextView) convertView.findViewById(R.id.tvContactName);
holder.number = (TextView) convertView.findViewById(R.id.tvContactNumber);
holder.checkbox = (CheckBox) convertView.findViewById(R.id.cbMultipleSelect);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.name.setText(contacts.get(position).name);
holder.number.setText(contacts.get(position).number);
holder.view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ContactInfo contact = new ContactInfo();
contact.id = contacts.get(position).id;
contact.name = contacts.get(position).name;
contact.number = contacts.get(position).number;
holder.checkbox.setChecked(!holder.checkbox.isChecked());
if(holder.checkbox.isChecked()) {
selectedContacts.add(contact);
} else {
selectedContacts.remove(contact);
}
}
});
return convertView;
}
private static class ViewHolder {
LinearLayout view;
CheckBox checkbox;
TextView name;
TextView number;
}
}
我做错了什么?请帮忙。
编辑:
完成@vinitius 要求我做的事情后,问题已解决,但当我滚动列表时,支票消失了。这是我的新 getView()
:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final ViewHolder holder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.contacts_list_row_item, null);
holder = new ViewHolder();
holder.view = (LinearLayout) convertView.findViewById(R.id.llContactRow);
holder.name = (TextView) convertView.findViewById(R.id.tvContactName);
holder.number = (TextView) convertView.findViewById(R.id.tvContactNumber);
holder.checkbox = (CheckBox) convertView.findViewById(R.id.cbMultipleSelect);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.name.setText(contacts.get(position).name);
holder.number.setText(contacts.get(position).number);
holder.checkbox.setChecked(selectedContacts.contains(contacts.get(position)));
holder.view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ContactInfo contact = new ContactInfo();
contact.id = contacts.get(position).id;
contact.name = contacts.get(position).name;
contact.number = contacts.get(position).number;
holder.checkbox.setChecked(!holder.checkbox.isChecked());
if(holder.checkbox.isChecked()) {
selectedContacts.add(contact);
} else {
selectedContacts.remove(contact);
}
}
});
return convertView;
}
您的问题是您需要将 holder.checkbox.setChecked() 设置为以下行下方的值:
holder.number.setText(contacts.get(position).number);
当前您在检查它时更改它的值,但您需要在调用 getview 方法时设置该值,否则它将保留之前的任何值。
如果您的联系人信息中有一个 'selected' 值而不是管理一个新列表,那可能是最好的。这样你就可以做类似的事情:
holder.checkbox.setChecked(contacts.get(position).isSelected);
您没有在 getView()
中显示您的内容。执行以下操作:
@Override
public void onClick(View v) {
//remove the other stuff. You don't want to create new instances here, otherwise you won't be able to remove them later
holder.checkbox.setChecked(!holder.checkbox.isChecked());
if(holder.checkbox.isChecked()) {
selectedContacts.add(contact.get(position));
} else {
selectedContacts.remove(contact.get(position));
}
}
并在为 LinearLayout
设置 OnClickListener
之前执行此操作:
holder.checkbox.setChecked(selectedContacts.contains(contacts.get(position)));
如果您希望在点击 CheckBox
时有相同的行为,只需添加到您的 CheckBox
xml:
android:clickable="false"
所以linearLayout
可以拦截它