使用复选框和搜索实现处理列表视图
handle list view with check box and search implemention
我有一个列表视图,每行都有一个复选框,我已经实现了一个搜索视图来在列表视图中进行搜索。问题是,当我从修改后的列表中搜索列表视图和位置 X 处的 select 项目时,从搜索视图中删除文本,我看到原始列表中的项目已在位置 X 中选中。
示例 - a,b,c....z 的列表。
我可以在列表中看到 5 个项目:
一个
乙
C
丁
E
然后搜索 z 所以我只看到 Z 并检查它。然后我删除 Z 并再次查看 A-E 并选中 A。
这是我的主要内容:
public class AddRoomatesScreen extends Activity implements AdapterView.OnItemClickListener,SearchView.OnQueryTextListener {
SharedPreferences preferences;
List<String> nameList = new ArrayList<String>();
List<String> phoneList = new ArrayList<String>();
MyAdapter adapter;
Button btnSelect;
String apartmentnumber;
SearchView searchView;
ArrayList<Contact> contactList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_roomate);
preferences = getSharedPreferences("appData", 0);
int apartmentNumber = preferences.getInt("apartmentNumber", 0);
apartmentnumber = Integer.toString(apartmentNumber);
getAllContacts(this.getContentResolver());
ListView lv = (ListView) findViewById(R.id.lv);
adapter = new MyAdapter(nameList,contactList);
lv.setAdapter(adapter);
lv.setOnItemClickListener(this);
lv.setItemsCanFocus(false);
lv.setTextFilterEnabled(true);
searchView = (SearchView) findViewById(R.id.search_view);
searchView.setOnQueryTextListener(this);
// adding
btnSelect = (Button) findViewById(R.id.addSelectedContacts);
btnSelect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(int i = 0; i<adapter.mCheckStates.size(); i++){
Contact contact = (adapter.contactsListCopy.get(adapter.mCheckStates.keyAt(i)));
new addRoommate().execute(apartmentnumber, contact.getPhoneNumber());
}
preferences = getSharedPreferences("appData", 0);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("roomatesLoadedFromDB", false);
editor.apply();
}
});
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
adapter.toggle(arg2);
}
public void getAllContacts(ContentResolver cr) {
Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
while (phones.moveToNext()) {
String name = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
nameList.add(name);
phoneList.add(phoneNumber);
contactList.add(new Contact(name,phoneNumber));
}
phones.close();
}
这是我的适配器:
class MyAdapter extends BaseAdapter implements CompoundButton.OnCheckedChangeListener,Filterable {
private SparseBooleanArray mCheckStates;
LayoutInflater mInflater;
TextView tv;
CheckBox cb;
ValueFilter filter;
ArrayList<Contact> contactsList;
ArrayList<Contact> contactsListCopy;
MyAdapter(List<String> nameList , ArrayList<Contact> contactsList) {
mCheckStates = new SparseBooleanArray(contactsList.size());
mInflater = (LayoutInflater) AddRoomatesScreen.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.contactsList = contactsList;
this.contactsListCopy = this.contactsList;
getFilter();
}
@Override
public int getCount() {
return contactsListCopy.size();
}
@Override
public Object getItem(int position) {
return contactsListCopy.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View vi = convertView;
if (convertView == null)
vi = mInflater.inflate(R.layout.contact_list_item, null);
TextView tv = (TextView) vi.findViewById(R.id.textView3);
cb = (CheckBox) vi.findViewById(R.id.checkBox);
Contact contact = contactsListCopy.get(position);
tv.setText(contact.getName());
cb.setTag(position);
cb.setChecked(mCheckStates.get(position, false));
cb.setOnCheckedChangeListener(this);
return vi;
}
public boolean isChecked(int position) {
return mCheckStates.get(position, false);
}
public void setChecked(int position, boolean isChecked) {
mCheckStates.put(position, isChecked);
notifyDataSetChanged();
}
public void toggle(int position) {
setChecked(position, !isChecked(position));
}
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
mCheckStates.put((Integer) buttonView.getTag(), isChecked);
}
@Override
public Filter getFilter() {
if (filter == null){
filter = new ValueFilter();
}
return filter;
}
private class ValueFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
ArrayList<Contact> temp = new ArrayList<Contact>();
for (int i = 0; i < contactList.size(); i++) {
Contact c = contactList.get(i);
if ((c.getName().toString())
.contains(constraint.toString())) {
temp.add(c);
}
}
results.count = temp.size();
results.values = temp;
} else {
results.count = contactList.size();
results.values = contactList;
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
contactsListCopy = (ArrayList<Contact>) results.values;
notifyDataSetChanged();
}
}
}
这是我的模型:
public class Contact{
private String phoneNumber;
private String name;
public Contact(String name , String phoneNumber){
this.phoneNumber = phoneNumber;
this.name = name;
}
public String getName() {
return name;
}
public String getPhoneNumber() {
return phoneNumber;
}
}
编辑:
您可以使用光标中的 ID 作为您的唯一 ID。
此代码将与下面最初发布的代码一起使用。
将 id 添加到您的联系人 class:
public class Contact{
private long id;
private String phoneNumber;
private String name;
public Contact(long id, String name , String phoneNumber) {
this.id = id;
this.phoneNumber = phoneNumber;
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public String getPhoneNumber() {
return phoneNumber;
}
}
这是从游标获取 ID 的方法:
public void getAllContacts(ContentResolver cr) {
Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
while (phones.moveToNext()) {
long id = phones.getLong(phones.getColumnIndex(ContactsContract.Data._ID));
String name = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
nameList.add(name);
phoneList.add(phoneNumber);
contactList.add(new Contact(id, name, phoneNumber));
}
phones.close();
}
您在适配器中的 mCheckStates
更改为:
private LongSparseArray<Boolean> mCheckStates;
下面的一些原始答案已更改以匹配用于 id 的 long
类型。
问题是您的 mCheckStates
布尔映射在过滤后未与 contactsListCopy
保持同步。
- 您筛选了 Z,因此 Z 现在是项目 0,
- 您勾选了设置位置 0 的 Z,
- 您重新显示整个列表。现在 A 是位置 0,所以它显示为已选中。
您需要跟踪已检查的联系人,而不是跟踪已检查的职位。为此,您需要使用联系人记录中的唯一 ID。
以下是您需要进行的更改:
让您的适配器使用唯一 ID:
@Override
public long getItemId(int position) {
return contactsListCopy.get(position).getId();
}
现在您的 activity 必须使用唯一 ID 而不是位置:
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
adapter.toggle(arg3);
}
在您的适配器 getView()
中,您现在必须使用复选框的 ID
cb.setTag(contact.getId());
cb.setChecked(mCheckStates.get(contact.getId(), false));
为了避免混淆,我会更改一些其他方法:
public boolean isChecked(long id) {
return mCheckStates.get(id, false);
}
public void setChecked(long id, boolean isChecked) {
mCheckStates.put(id, isChecked);
notifyDataSetChanged();
}
public void toggle(long id) {
setChecked(id, !isChecked(id));
}
我有一个列表视图,每行都有一个复选框,我已经实现了一个搜索视图来在列表视图中进行搜索。问题是,当我从修改后的列表中搜索列表视图和位置 X 处的 select 项目时,从搜索视图中删除文本,我看到原始列表中的项目已在位置 X 中选中。
示例 - a,b,c....z 的列表。
我可以在列表中看到 5 个项目:
一个 乙 C 丁 E
然后搜索 z 所以我只看到 Z 并检查它。然后我删除 Z 并再次查看 A-E 并选中 A。
这是我的主要内容:
public class AddRoomatesScreen extends Activity implements AdapterView.OnItemClickListener,SearchView.OnQueryTextListener {
SharedPreferences preferences;
List<String> nameList = new ArrayList<String>();
List<String> phoneList = new ArrayList<String>();
MyAdapter adapter;
Button btnSelect;
String apartmentnumber;
SearchView searchView;
ArrayList<Contact> contactList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_roomate);
preferences = getSharedPreferences("appData", 0);
int apartmentNumber = preferences.getInt("apartmentNumber", 0);
apartmentnumber = Integer.toString(apartmentNumber);
getAllContacts(this.getContentResolver());
ListView lv = (ListView) findViewById(R.id.lv);
adapter = new MyAdapter(nameList,contactList);
lv.setAdapter(adapter);
lv.setOnItemClickListener(this);
lv.setItemsCanFocus(false);
lv.setTextFilterEnabled(true);
searchView = (SearchView) findViewById(R.id.search_view);
searchView.setOnQueryTextListener(this);
// adding
btnSelect = (Button) findViewById(R.id.addSelectedContacts);
btnSelect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(int i = 0; i<adapter.mCheckStates.size(); i++){
Contact contact = (adapter.contactsListCopy.get(adapter.mCheckStates.keyAt(i)));
new addRoommate().execute(apartmentnumber, contact.getPhoneNumber());
}
preferences = getSharedPreferences("appData", 0);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("roomatesLoadedFromDB", false);
editor.apply();
}
});
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
adapter.toggle(arg2);
}
public void getAllContacts(ContentResolver cr) {
Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
while (phones.moveToNext()) {
String name = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
nameList.add(name);
phoneList.add(phoneNumber);
contactList.add(new Contact(name,phoneNumber));
}
phones.close();
}
这是我的适配器:
class MyAdapter extends BaseAdapter implements CompoundButton.OnCheckedChangeListener,Filterable {
private SparseBooleanArray mCheckStates;
LayoutInflater mInflater;
TextView tv;
CheckBox cb;
ValueFilter filter;
ArrayList<Contact> contactsList;
ArrayList<Contact> contactsListCopy;
MyAdapter(List<String> nameList , ArrayList<Contact> contactsList) {
mCheckStates = new SparseBooleanArray(contactsList.size());
mInflater = (LayoutInflater) AddRoomatesScreen.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.contactsList = contactsList;
this.contactsListCopy = this.contactsList;
getFilter();
}
@Override
public int getCount() {
return contactsListCopy.size();
}
@Override
public Object getItem(int position) {
return contactsListCopy.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View vi = convertView;
if (convertView == null)
vi = mInflater.inflate(R.layout.contact_list_item, null);
TextView tv = (TextView) vi.findViewById(R.id.textView3);
cb = (CheckBox) vi.findViewById(R.id.checkBox);
Contact contact = contactsListCopy.get(position);
tv.setText(contact.getName());
cb.setTag(position);
cb.setChecked(mCheckStates.get(position, false));
cb.setOnCheckedChangeListener(this);
return vi;
}
public boolean isChecked(int position) {
return mCheckStates.get(position, false);
}
public void setChecked(int position, boolean isChecked) {
mCheckStates.put(position, isChecked);
notifyDataSetChanged();
}
public void toggle(int position) {
setChecked(position, !isChecked(position));
}
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
mCheckStates.put((Integer) buttonView.getTag(), isChecked);
}
@Override
public Filter getFilter() {
if (filter == null){
filter = new ValueFilter();
}
return filter;
}
private class ValueFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
ArrayList<Contact> temp = new ArrayList<Contact>();
for (int i = 0; i < contactList.size(); i++) {
Contact c = contactList.get(i);
if ((c.getName().toString())
.contains(constraint.toString())) {
temp.add(c);
}
}
results.count = temp.size();
results.values = temp;
} else {
results.count = contactList.size();
results.values = contactList;
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
contactsListCopy = (ArrayList<Contact>) results.values;
notifyDataSetChanged();
}
}
}
这是我的模型:
public class Contact{
private String phoneNumber;
private String name;
public Contact(String name , String phoneNumber){
this.phoneNumber = phoneNumber;
this.name = name;
}
public String getName() {
return name;
}
public String getPhoneNumber() {
return phoneNumber;
}
}
编辑:
您可以使用光标中的 ID 作为您的唯一 ID。
此代码将与下面最初发布的代码一起使用。
将 id 添加到您的联系人 class:
public class Contact{
private long id;
private String phoneNumber;
private String name;
public Contact(long id, String name , String phoneNumber) {
this.id = id;
this.phoneNumber = phoneNumber;
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public String getPhoneNumber() {
return phoneNumber;
}
}
这是从游标获取 ID 的方法:
public void getAllContacts(ContentResolver cr) {
Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
while (phones.moveToNext()) {
long id = phones.getLong(phones.getColumnIndex(ContactsContract.Data._ID));
String name = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
nameList.add(name);
phoneList.add(phoneNumber);
contactList.add(new Contact(id, name, phoneNumber));
}
phones.close();
}
您在适配器中的 mCheckStates
更改为:
private LongSparseArray<Boolean> mCheckStates;
下面的一些原始答案已更改以匹配用于 id 的 long
类型。
问题是您的 mCheckStates
布尔映射在过滤后未与 contactsListCopy
保持同步。
- 您筛选了 Z,因此 Z 现在是项目 0,
- 您勾选了设置位置 0 的 Z,
- 您重新显示整个列表。现在 A 是位置 0,所以它显示为已选中。
您需要跟踪已检查的联系人,而不是跟踪已检查的职位。为此,您需要使用联系人记录中的唯一 ID。
以下是您需要进行的更改:
让您的适配器使用唯一 ID:
@Override
public long getItemId(int position) {
return contactsListCopy.get(position).getId();
}
现在您的 activity 必须使用唯一 ID 而不是位置:
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
adapter.toggle(arg3);
}
在您的适配器 getView()
中,您现在必须使用复选框的 ID
cb.setTag(contact.getId());
cb.setChecked(mCheckStates.get(contact.getId(), false));
为了避免混淆,我会更改一些其他方法:
public boolean isChecked(long id) {
return mCheckStates.get(id, false);
}
public void setChecked(long id, boolean isChecked) {
mCheckStates.put(id, isChecked);
notifyDataSetChanged();
}
public void toggle(long id) {
setChecked(id, !isChecked(id));
}