使用复选框和搜索实现处理列表视图

时间:2016-07-20 16:57:00

标签: android listview searchview checkboxlist

我有一个列表视图,每行都有一个复选框,我已经实现了一个serch视图来搜索列表视图。问题是当我搜索列表视图并从修改后的列表中选择位置X处的项目时,从搜索视图中删除文本,我会看到原始列表,并在位置X中选中项目。

示例 - a,b,c .... z。

的列表

我可以在列表中看到5个项目:

一个 乙 C d ë

然后搜索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;
    }

}

1 个答案:

答案 0 :(得分:4)

编辑:

您可以使用光标中的ID作为唯一ID。

此代码将使用下面最初发布的代码。

将ID添加到您的Contact类:

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,
  • 您检查了Z,将位置0设置为已选中,
  • 您重新显示整个列表。现在A是位置0,因此显示为已选中。

您需要跟踪已检查的联系人,而不是跟踪已检查的位置。为此,您需要使用联系人记录中的唯一ID。

以下是您需要做出的更改:

使您的适配器使用唯一ID:

    @Override
    public long getItemId(int position) {
        return contactsListCopy.get(position).getId(); 
    }

现在您的活动必须使用唯一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));
    }