ListView单选多选

来源:互联网 发布:vr编辑软件 编辑:程序博客网 时间:2024/06/03 11:16

Android中,ListView可以设置choiceMode,可见Android对ListView的单选或多选是有进行封装的,然而我看到的许多单选或多选的ListView,包括我搭档以前写的例子,以前几个老外封装的库,都是自己维护了一个集合,用于存放每个item的选中状态。这样一来,不但代码显得繁复,逻辑上也成冗余,而且容易出BUG。
其实,ListView中,已经自己维护了一个SparseBooleanArray,用于保存每一项的选中状态。而对于每一项,它是通过adapter的getView中获取的view,来设置它的选中状态的。所以,我们需要使得adapter中,getView中返回的这个view实现Checkable接口。下面,将介绍具体实现。
要想实现单选和多选首先这个item的布局很重要

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content">    <RadioButton        android:id="@+id/checkedView"        android:layout_centerVertical="true"        android:layout_alignParentLeft="true"        android:layout_width="wrap_content"        android:layout_height="48dp" />    <TextView        android:id="@+id/text"        android:gravity="center_vertical"        android:layout_alignParentRight="true"        android:layout_width="wrap_content"        android:layout_height="48dp" /></RelativeLayout>

自定义的布局

import android.content.Context;import android.view.View;import android.widget.Checkable;import android.widget.FrameLayout;import android.widget.RadioButton;import android.widget.TextView;/** * Created by xuenan on 2016/7/13. */public class ChoiceView extends FrameLayout implements Checkable{    private TextView mTextView;    private RadioButton mRadioButton;    public ChoiceView(Context context) {        super(context);        View.inflate(context, R.layout.item_single_choice, this);        mTextView = (TextView) findViewById(R.id.text);        mRadioButton = (RadioButton) findViewById(R.id.checkedView);    }    public void setText(String text) {        mTextView.setText(text);    }    @Override    public void setChecked(boolean checked) {        mRadioButton.setChecked(checked);    }    @Override    public boolean isChecked() {        return mRadioButton.isChecked();    }    @Override    public void toggle() {        mRadioButton.toggle();    }}

还有Adapter中的处理

import android.content.Context;import android.util.SparseArray;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.Checkable;import android.widget.FrameLayout;import android.widget.TextView;import java.util.Arrays;import java.util.List;/** * 可选择的ListAdapter. */public abstract class ChoiceListAdapter<T> extends BaseAdapter {    private Context mContext;    protected List<T> mData;    private int mLayoutId;    private int[] mChoiceId;    /**     * @param context     * @param layoutId item 的布局id.     * @param data     数据源     * @param choiceId 选择控件的id     */    public ChoiceListAdapter(Context context, int layoutId, List<T> data, int... choiceId) {        mContext = context;        mData = data;        mLayoutId = layoutId;        mChoiceId = choiceId;    }    /**     * @param context     * @param layoutId The layout id if the item view.     * @param data     data source     * @param choiceId checkable view id     */    public ChoiceListAdapter(Context context, int layoutId, T[] data, int... choiceId) {        this(context, layoutId, Arrays.asList(data), choiceId);    }    @Override    public int getCount() {        return mData == null ? 0 : mData.size();    }    @Override    public T getItem(int position) {        return mData == null ? null : mData.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        final ChoiceLayout view;        if (convertView == null) {            view = new ChoiceLayout(mContext);            view.setLayoutAndChoiceId(mLayoutId, mChoiceId);            holdView(view);        } else {            view = (ChoiceLayout) convertView;        }        bindData(view, position, mData.get(position));        return view;    }    /**     * 持有item的子view。在该方法内调用ChoiceView的hold方法,把子view添加进去。     *     * @param view ChoiceView     */    protected abstract void holdView(ChoiceLayout view);    /**     * 绑定数据     *     * @param view     * @param position     * @param data     */    protected abstract void bindData(ChoiceLayout view, int position, T data);    /**     * 绑定Checkable控件的Layout.     */    public static class ChoiceLayout extends FrameLayout implements Checkable {        private Checkable[] mCheckViews;        private SparseArray<View> mHolderViews;        private boolean mChecked;        /**         * 是否强制设为选中状态         */        private boolean mForceChecked;        protected ChoiceLayout(Context context) {            super(context);            mHolderViews = new SparseArray<>();        }        /**         * 设置item的布局及Checkable控件的id。         *         * @param layoutId 布局id         * @param choiceId Checkable控件id         */        protected void setLayoutAndChoiceId(int layoutId, int... choiceId) {            View.inflate(getContext(), layoutId, this);            mCheckViews = new Checkable[choiceId.length];            for (int i = 0; i < choiceId.length; i++) {                View checkedView = findViewById(choiceId[i]);                checkedView.setFocusable(false);                checkedView.setFocusableInTouchMode(false);                checkedView.setClickable(false);                mHolderViews.put(choiceId[i], checkedView);                mCheckViews[i] = (Checkable) checkedView;            }        }        /**         * 持有子view         *         * @param id         */        public void hold(int id) {            mHolderViews.put(id, findViewById(id));        }        /**         * 获取子view。         *         * @param id         * @param <V>         * @return 返回指定的id对应的view。         */        public <V> V get(int id) {            return (V) mHolderViews.get(id);        }        public void setText(int id, int stringId) {            TextView textView = get(id);            textView.setText(stringId);        }        public void setText(int id, String text) {            TextView textView = get(id);            textView.setText(text);        }        public void setChecked(int id, boolean checked) {            Checkable checkable = get(id);            checkable.setChecked(checked);        }        @Override        public void setChecked(boolean checked) {            checked |= mForceChecked;            for (Checkable checkable : mCheckViews) {                checkable.setChecked(checked);            }            mChecked = checked;        }        @Override        public boolean isChecked() {            return mChecked;        }        /**         * 是否为强制选中状态。         *         * @return 如果是强制选中状态返回true,否则返回false。         */        public boolean isForceChecked() {            return mForceChecked;        }        /**         * 设置是否强制选中状态。         *         * @param forceChecked 是否强制选中状态。         */        public void setForceChecked(boolean forceChecked) {            mForceChecked = forceChecked;        }        @Override        public void toggle() {            setChecked(mForceChecked | !mChecked);        }    }}

单选模式的使用,布局里边就一个listView就不贴了

import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.AdapterView;import android.widget.ListView;import android.widget.TextView;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class SingleActivity extends AppCompatActivity {    private ListView mListView;    private ChoiceListAdapter adapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        this.setContentView(R.layout.activity_choice_list2);        mListView = (ListView) findViewById(android.R.id.list);        mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);//设置单选模式        List<String> data = new ArrayList<>();        for (int i = 0; i < 5; i++) {            data.add("test" + i);        }        adapter = new ChoiceListAdapter<String>(this, R.layout.item_single_choice,                data, R.id.checkedView) {            @Override            protected void holdView(ChoiceLayout view) {                view.hold(R.id.text);            }            @Override            protected void bindData(ChoiceLayout view, int position, String data) {                TextView text = view.get(R.id.text);                text.setText(data);            }        };        mListView.setAdapter(adapter);        mListView.setItemChecked(0,true);//设置默认选中第一个        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view,                                    int position, long id) {                if (ListView.CHOICE_MODE_SINGLE == mListView.getChoiceMode()) {                    String item_data = (String) mListView                            .getItemAtPosition(position);                    Toast.makeText(SingleActivity.this,                            "当前为单选模式\n选中条目的数据:" + item_data,Toast.LENGTH_SHORT).show();                }            }        });    }}

//多选模式的使用布局中一个listView 两个按钮 也不写了

import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.util.SparseBooleanArray;import android.view.View;import android.widget.AdapterView;import android.widget.ListView;import android.widget.TextView;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class MultActivity extends AppCompatActivity {    private View mChoiceAll;    private View mReverseChoice;    private ListView mListView;    private ChoiceListAdapter adapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        this.setContentView(R.layout.activity_choice_list);        mChoiceAll = findViewById(R.id.all);        mReverseChoice = findViewById(R.id.reverse);        mListView = (ListView) findViewById(android.R.id.list);        mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);//设置多选模式        List<String> data = new ArrayList<>();        for (int i = 0; i < 5; i++) {            data.add("test" + i);        }        adapter = new ChoiceListAdapter<String>(this, R.layout.item_single_choice,                data, R.id.checkedView) {            @Override            protected void holdView(ChoiceLayout view) {                view.hold(R.id.text);            }            @Override            protected void bindData(ChoiceLayout view, int position, String data) {                TextView text = view.get(R.id.text);                text.setText(data);            }        };        mListView.setAdapter(adapter);        //全选        mChoiceAll.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                final int size = adapter.getCount();                for (int i = 0; i < size; i++) {                    mListView.setItemChecked(i, true);                }                Toast.makeText(                        MultActivity.this,                        "当前为多选模式\n选中的条数:" + mListView.getCheckedItemCount(),                        Toast.LENGTH_SHORT).show();                SparseBooleanArray sparseBooleanArray = mListView.getCheckedItemPositions();                ArrayList<String> list = GetPOsitions(sparseBooleanArray);                for (int i = 0; i < list.size(); i++) {                    Log.e("------", list.get(i));                }            }    });        //反选        mReverseChoice.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                SparseBooleanArray checkedItems = mListView.getCheckedItemPositions();                final int size = adapter.getCount();                for (int i = 0; i < size; i++) {                    mListView.setItemChecked(i, !checkedItems.get(i));                }            }        });        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view,                                    int position, long id) {                if (ListView.CHOICE_MODE_MULTIPLE == mListView.getChoiceMode()) {                    String item =(String) mListView.getItemAtPosition(position);                    Toast.makeText(                            MultActivity.this,                            "当前为多选模式\n选中的条数:" + mListView.getCheckedItemCount()                                    + "\n" + "点击的数据:" + item,Toast.LENGTH_SHORT)                            .show();                    SparseBooleanArray sparseBooleanArray = mListView.getCheckedItemPositions();                    ArrayList<String> list = GetPOsitions(sparseBooleanArray);                    for(int i=0;i<list.size();i++){                        Log.e("------",list.get(i));                    }                }            }        });    }    //保存选中项的方法    private ArrayList<String> GetPOsitions(SparseBooleanArray sparseBooleanArray){        ArrayList<String>strings = new ArrayList<>();        String sss = sparseBooleanArray.toString();        String sss_s = sss.substring(1,sss.length()-1);        String [] xx = sss_s.split(",");        for(int j=0;j<xx.length;j++){            if(xx[j].contains("true")){                strings.add(xx[j].trim().substring(0,xx[j].trim().length()-5));            }        }        return strings;    }}
0 0
原创粉丝点击