过滤Listview数据后,勾选(选中)复选框的位置会发生变化

时间:2012-12-22 08:49:17

标签: android listview filter baseadapter

我尝试根据BaseAdapter中的文字过滤输入并检查EditText,在我的自定义适配器上应用过滤器,扩展CheckBox我面临一些问题}选择一个值,如果我删除EditText中的文本以搜索其他内容,则选中复选框的位置会自动更改,如下图所示。我目前面临两个问题

1 - 勾选复选框的位置会自动更改

2 - 如果我在EditText中输入大写,则ListView会变为空白。

public class MyCustomAdapter extends BaseAdapter implements Filterable {

Context mContext;
private LayoutInflater mInflater;
SparseBooleanArray mSparseBooleanArray;
private ArrayList<Map<String,String>> mAdapData = new ArrayList<Map<String, String>>();
private ArrayList<Map<String,String>> mOriginalData = new ArrayList<Map<String, String>>();

public MyCustomAdapter(Context mContext) {
    mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    mSparseBooleanArray = new SparseBooleanArray();
}

public ArrayList<String> getCheckedItems() {
    ArrayList<String> mTempArry = new ArrayList<String>();
    for (int i = 0; i < mAdapData.size(); i++) {
        if (mSparseBooleanArray.get(i)) {
            Map<String, String> map = (Map<String, String>) mAdapData.get(i);
            final String numbr = map.get("Phone").toString();
            mTempArry.add(numbr);
        }
    }
    return mTempArry;
}

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

public void addItem(String paramString1, String paramString2) {
    Map<String, String> NameNumber = new HashMap<String, String>();
    NameNumber.put("Name", paramString1);
    NameNumber.put("Phone", paramString2);
    this.mAdapData.add(NameNumber);
    this.mOriginalData.add(NameNumber);
    notifyDataSetChanged();
}

@SuppressWarnings("unchecked")
public Object getItem(int paramInt) {
    return (ArrayList<Map<String, String>>) this.mAdapData.get(paramInt);
}

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

@Override
public View getView(final int paramInt, View paramView, ViewGroup paramViewGroup) {

    ViewHolder viewHolder;

    if (paramView == null) {
        viewHolder = new ViewHolder();
        paramView = mInflater.inflate(R.layout.multiplecontactview, null);
        viewHolder.tvName = (TextView) paramView.findViewById(R.id.txtContactName);
        viewHolder.tvNumber = (TextView) paramView.findViewById(R.id.txtContactNumber);
        viewHolder.cb = (CheckBox) paramView.findViewById(R.id.checkBox1);
        viewHolder.cb.setTag(paramInt);
        viewHolder.cb.setChecked(mSparseBooleanArray.get(paramInt));
        viewHolder.cb.setOnCheckedChangeListener(mCheckedChangeListener);
        viewHolder.tvName.setTextColor(Color.BLACK);
        viewHolder.tvNumber.setTextColor(Color.BLACK);
        for (int i = 0; i < mAdapData.size(); i++) {
            Map<String, String> map = (Map<String, String>) mAdapData.get(paramInt);
            final String name = map.get("Name").toString();
            final String numbr = map.get("Phone").toString();
            viewHolder.tvName.setText(name);
            viewHolder.tvNumber.setText(numbr);
        }
        paramView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) paramView.getTag();
    }       
    return paramView;
}

OnCheckedChangeListener mCheckedChangeListener = new OnCheckedChangeListener() {
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        mSparseBooleanArray.put((Integer) buttonView.getTag(), isChecked);
    }
};

public static class ViewHolder {
    TextView tvName;
    TextView tvNumber;
    CheckBox cb;
}

@Override
public Filter getFilter() {
    return new MyContactFilter();
}

@SuppressLint("DefaultLocale")
private class MyContactFilter extends Filter {

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults results = new FilterResults();
        ArrayList<Map<String, String>> mFilteredData = new ArrayList<Map<String, String>>();

        if (!TextUtils.isEmpty(constraint)) { 
            for(int i = 0; i < mAdapData.size(); i++) {
                Map<String, String> map = (Map<String, String>) mAdapData.get(i);
                final String names = map.get("Name").toString();
                final String numbr = map.get("Phone").toString();
                if(names.toLowerCase().contains(constraint.toString().toLowerCase())) {
                    Map<String, String> FilNameNumber = new HashMap<String, String>();
                    FilNameNumber.put("Name", names);
                    FilNameNumber.put("Phone", numbr);
                    mFilteredData.add(FilNameNumber);
                }
            }
            results.values = mFilteredData;
            results.count = mFilteredData.size();

        } else {
            synchronized (mOriginalData) {
                results.values = mOriginalData;
                results.count = mOriginalData.size();
            }
        }
        return results;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence cs, FilterResults fr) {
        mAdapData = (ArrayList<Map<String, String>>) fr.values;
        notifyDataSetChanged();
    }
}
}

Screenshot

2 个答案:

答案 0 :(得分:2)

去掉复杂的映射以跟踪属性,将数据存储在这样的类中,以及检查状态:

public class Data {
 private final String text;
 private boolean checked;

 public Data(String text){
   this.text = text;
   this.checked = false;
 }

 public void setChecked(boolean b){
   this.checked = b;
 }

 public boolean isChecked(){
   return this.checked;
 }

 public String getText(){
   return this.text;
 }
}

getView()内,根据数据状态设置复选框,添加监听器以修改数据状态:

final Data data = getItem(position);

cb.setOnCheckedChangeListener(null); //important 
cb.setChecked(data.isChecked());
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        data.setChecked(isChecked);
    }
});

关于过滤:

names.toLowerCase().contains(cs)

Contains char值进行区分大小写匹配。试试names.toLowerCase().contains(cs.toLowerCase())

答案 1 :(得分:1)

如果您更专注地查看代码,具体在getView()上,您会看到每次创建ViewHolder对象,而convertView存在。

使用ViewHolder模式是错误的。不是每次都创建它,而是仅在convertView为空时创建它,并按convertView将其设置为setTag()的标记,否则使用{{1}获取对ViewHolder的引用}}。就像这样:

getTag()

同样在 ViewHolder viewHolder; if (paramView == null) { paramView = mInflater.inflate(R.layout.multiplecontactview, null); viewHolder = new ViewHolder(); viewHolder.tvName = (TextView) paramView.findViewById(R.id.txtContactName); viewHolder.tvNumber = (TextView) paramView.findViewById(R.id.txtContactNumber); viewHolder.cb = (CheckBox) paramView.findViewById(R.id.checkBox1); paramView.setTag(viewHolder); } else { viewHolder = (ViewHolder) paramView.getTag(); } viewHolder.cb.setTag(paramInt); viewHolder.cb.setChecked(mSparseBooleanArray.get(paramInt)); viewHolder.cb.setOnCheckedChangeListener(mCheckedChangeListener); viewHolder.tvName.setTextColor(Color.BLACK); viewHolder.tvNumber.setTextColor(Color.BLACK); for (int i = 0; i < mAdapData.size(); i++) { Map<String, String> map = (Map<String, String>) mAdapData.get(paramInt); final String name = map.get("Name").toString(); final String numbr = map.get("Phone").toString(); viewHolder.tvName.setText(name); viewHolder.tvNumber.setText(numbr); } return paramView; 尝试更改此代码段:

preformFiltering()

if (names.toLowerCase().contains(cs))

更新

有一些奇怪的代码片段:

if (names.toLowerCase().contains(cs.toString().toLowerCase()))

这意味着如果您第一次检查列表中0位置的列表项,则OnCheckedChangeListener mCheckedChangeListener = new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { mSparseBooleanArray.put((Integer) buttonView.getTag(), isChecked); } }; 表示SparseArray的第一项应始终具有复选框,因为如果您没有在代码中的任何位置取消选中它,请不要将该值设置为false,但仅在用户手动取消选中该复选框时才执行此操作。