ListView单选多选

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;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_28963915/article/details/51907441