使用ListView中的CheckBox和Android上的Filterable

时间:2015-08-03 15:24:28

标签: android listview checkbox filter

在本教程(http://www.tutorialsbuzz.com/2014/08/filter-custom-listviewbaseadapter.html)中,我可以根据ListView输入过滤EditText中的项目:

结果与预期完美结合。但是,当我尝试将CheckBox放入ListView项时,事情就会失控。以下是我对教程中源代码的修改。

Country.java

public class Country {

    String name;
    String iso_code;
    int flag;
    Boolean checked;

    Country(String name, String iso_code, int flag, Boolean checked) {
        this.name = name;
        this.iso_code = iso_code;
        this.flag = flag;
        this.checked = checked;
    }

    public String getIso_code() {
        return iso_code;
    }

    public void setIso_code(String iso_code) {
        this.iso_code = iso_code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getFlag() {
        return flag;
    }

    public void setFlag(int flag) {
        this.flag = flag;
    }

    public Boolean getChecked() {
        return checked;
    }

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

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="2dp">

    <ImageView
        android:id="@+id/flag"
        android:layout_width="80dp"
        android:layout_height="70dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"/>

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:layout_toRightOf="@+id/flag"
        android:paddingBottom="10dp"
        android:text="txt"
        android:textColor="#000000"
        android:textSize="20sp"/>

    <TextView
        android:id="@+id/code"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/name"
        android:layout_below="@+id/name"
        android:layout_marginLeft="5dp"
        android:text="txt"
        android:textColor="#000000"
        android:textSize="16sp"/>

    <CheckBox
        android:id="@+id/checkBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="16dp"/>

</RelativeLayout>

CustomAdapter.java

public class CustomAdapter extends BaseAdapter implements Filterable {

    Context context;
    ArrayList<Country> countrylist;
    ArrayList<Country> mStringFilterList;
    ValueFilter valueFilter;

    CustomAdapter(Context context , ArrayList<Country> countrylist) {
        this.context = context;
        this.countrylist = countrylist;
        mStringFilterList = countrylist;
    }

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

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

    @Override
    public long getItemId(int position) {
        return countrylist.indexOf(getItem(position));
    }

    @Override
    public View getView(int position , View convertView , ViewGroup parent ) {

        LayoutInflater mInflater = (LayoutInflater) context
                .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

        convertView = null;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.list_item, null);

            TextView name_tv = (TextView) convertView.findViewById(R.id.name);
            TextView iso_tv = (TextView) convertView.findViewById(R.id.code);
            ImageView iv = (ImageView) convertView.findViewById(R.id.flag);
            CheckBox cb = (CheckBox) convertView.findViewById(R.id.checkBox);

            Country country = countrylist.get(position);

            name_tv.setText(country.getName());
            iso_tv.setText(country.getIso_code());
            iv.setImageResource(country.getFlag());

            cb.setChecked(country.getChecked());
            cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        country.setChecked(isChecked);
    }
});


        }
        return convertView;
    }

    @Override
    public Filter getFilter() {
        if (valueFilter == null) {
            valueFilter = new ValueFilter();
        }
        return valueFilter;
    }

    private class ValueFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults();

            if (constraint != null && constraint.length() > 0) {
                ArrayList<Country> filterList = new ArrayList<Country>();
                for (int i = 0; i < mStringFilterList.size(); i++) {
                    if ( (mStringFilterList.get(i).getName().toUpperCase() )
                            .contains(constraint.toString().toUpperCase())) {

                        Country country = new Country(mStringFilterList.get(i)
                                .getName() ,  mStringFilterList.get(i)
                                .getIso_code() ,  mStringFilterList.get(i)
                                .getFlag());

                        filterList.add(country);
                    }
                }
                results.count = filterList.size();
                results.values = filterList;
            } else {
                results.count = mStringFilterList.size();
                results.values = mStringFilterList;
            }
            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint,
                FilterResults results) {
            countrylist = (ArrayList<Country>) results.values;
            notifyDataSetChanged();
        }
    }
}

过滤时,CheckBox的状态几乎总是随机跳跃。我假设因为Country中的值已在运行时更改。知道如何以正确的方式实现这一点吗?

1 个答案:

答案 0 :(得分:0)

如果convertView已存在,则不会更新视图。你应该这样做,唯一要忽略的是重新充气。 (顺便说一下,视图模式会大大改善这段代码。)

因为您永远不会更新视图,所以它意味着它会显示之前该位置的数据。

@Override
public View getView(int position , View convertView , ViewGroup parent ) {

    LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
    CheckBox cb = (ImageView) convertView.findViewById(R.id.checkBox);
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.list_item, null);
        cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                country.setChecked(isChecked);
            }
        });
    }

    TextView name_tv = (TextView) convertView.findViewById(R.id.name);
    ...
    cb.setChecked(country.getChecked());
    return convertView;
}

上面的代码在我看来它应该可以解决您的问题,但是对格式化感到宽容,我正在通过手机进行编辑。将来你可以使用它来查看可检查的界面和列表视图,应该为你节省一些代码(并且让人头痛)