[基础控件]---自定义Dilaog中包含ListView实现对CheckBox的单选、多选、全选/全不选、反选

1、首先明确要实现的功能:一个Dialog包含有ListView,每个item都是一个CheckBox。此Dialog可实现对CheckBox的单选、多选、全选、全不选、反选

    照旧,先上图:

001  002  003  004反选

先做一下说明,第一张图是dialog主界面没有进行任何操作,第二张图是单选与多选、第三张图是全选与全不选、第四张图是反选

2、布局说明:此自定义Dialog实为一个Activity,style设置为Theme.Dialog

Dialog的布局

<?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="match_parent" >



    <LinearLayout

        android:id="@+id/dialogActivity_title"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:background="@android:color/darker_gray"

        android:orientation="horizontal" >



        <Button

            android:id="@+id/dialogActivity_selectAll"

            android:layout_width="0dp"

            android:layout_height="wrap_content"

            android:layout_weight="0.5"

            android:onClick="doClick"

            android:text="全选/全不选" />



        <Button

            android:id="@+id/dialogActivity_Invert"

            android:layout_width="0dp"

            android:layout_height="wrap_content"

            android:layout_weight="0.5"

            android:onClick="doClick"

            android:text="反选" />

    </LinearLayout>



    <TableLayout

        android:id="@+id/dialogActivity_bottom"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_alignParentBottom="true"

        android:background="@android:color/darker_gray"

        android:orientation="vertical"

        android:stretchColumns="0,1" >



        <TextView

            android:id="@+id/dialogActivity_count"

            android:layout_marginLeft="12dp"

            android:text="总计"

            android:textColor="@android:color/black"

            android:textSize="18sp" />



        <TableRow

            android:layout_width="match_parent"

            android:layout_height="wrap_content" >



            <Button

                android:id="@+id/dialogActivity_sure"

                android:onClick="doClick"

                android:text="确定" />



            <Button

                android:id="@+id/dialogActivity_cancle"

                android:onClick="doClick"

                android:text="取消" />

        </TableRow>

    </TableLayout>



    <ListView

        android:id="@+id/dialogActivity_listView"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_above="@id/dialogActivity_bottom"

        android:layout_below="@id/dialogActivity_title" >

    </ListView>



</RelativeLayout>

item布局

<?xml version="1.0" encoding="utf-8"?>

<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@+id/select"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:background="#ededed"

    android:gravity="right|center_vertical"

    android:text="选择"

    android:textColor="@android:color/black"

    android:textSize="18sp" >

</CheckBox>

3、Dialog布局初始化很简单,而关键是①对每个item上的CheckBox状态切换的监听②在ListView外部选择全选/全不选、反选时ListView内部的CheckBox状态会随之改变。③将选中状态的item添加到被选中项集合中。④需要一个内部监听接口用于监听被选中项、与被选中项的总数。

总体思路,我们需要一个专门用来保存每个CheckBox的状态(boolean类型 true选中 false未选中)的Map集合,这个Map集合必须与ListView接收到的集合的个数必须保持一致。当某一个item上的CheckBox状态发生改变时。那么改变Map集合中与之对应的boolean类型值。最后遍历Map集合,如果某项为true,则获取与之对应项的对象 然后加入到被选中项的集合中去。所以这个ListVIew的adapter需要几个属性:private ArrayList<Student> receiveDatas;// 接收的数据 ,private Map<Integer, Boolean> map;// 保存被选中与否的状态的集合, private ArrayList<Student> selectedItems;// 被选中项的集合。 那么下面来解决第一个问题,对每一个item上的CheckBox状态切换的监听:在item对其布局上的控件CheckBox进行初始化后,立即设置监听,一旦被选中或被取消则变更选中状态。接着解决第二个问题,既然是外部的某项指令改变了ListView内部item选中状态,那么BaseAdapter需要提供一个public方法供外部调用而此方法专门用于修改item选中状态与否的修改+item界面更新+选中的item个数的监听。第三个问题就不做过多解释了,当map中的某项的状态为true时将与之对应的对象添加到selectedItems集合中。最后第四个问题,我们需要一个内部的回调接口用于监听每次状态变更,然后调用回调函数,将其展现在前台的Dialog中。

以上说了太多,表达能力有限,直接上源码吧。

public class StudentsApdater extends BaseAdapter {

    private ArrayList<Student> receiveDatas;// 接收的数据

    private OnSelectedItemChanged callBack;// 内部接口:监听选中项的个数(随着item被点击而改变)

    private LayoutInflater inflater;



    private Map<Integer, Boolean> map;// 保存被选中与否的状态的集合

    private ArrayList<Student> selectedItems;// 被选中项的集合



    /**

     * 构造方法

     * 

     * @param context

     * @param receiveDatas

     */

    public StudentsApdater(Context context, ArrayList<Student> receiveDatas,

            OnSelectedItemChanged callBack) {

        inflater = LayoutInflater.from(context);

        this.receiveDatas = receiveDatas;

        this.callBack = callBack;



        // 初始化被选中项

        map = new HashMap<Integer, Boolean>();

        for (int i = 0; i < receiveDatas.size(); i++) {

            map.put(i, false);

        }

        // 初始化被选中项的集合

        selectedItems = new ArrayList<Student>();

    }



    /**

     * 数据的设置

     * 

     * @param receiveDatas

     */

    public void setDatas(ArrayList<Student> receiveDatas) {

        this.receiveDatas = receiveDatas;

    }



    @Override

    public int getCount() {

        // TODO Auto-generated method stub

        return receiveDatas.size();

    }



    @Override

    public Student getItem(int position) {

        // TODO Auto-generated method stub

        return receiveDatas.get(position);

    }



    @Override

    public long getItemId(int position) {

        // TODO Auto-generated method stub

        return receiveDatas.get(position).getId();

    }



    @Override

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

        // 1.1、初始化ViewHolder控件

        ViewHolder holder = null;

        // 1.2、初始化控件属性

        if (convertView == null) {

            convertView = inflater.inflate(R.layout.item_select, null);

            holder = new ViewHolder();

            holder.cb = (CheckBox) convertView.findViewById(R.id.select);

            convertView.setTag(holder);

        } else {

            holder = (ViewHolder) convertView.getTag();

        }



        // 2.1获取对象

        final Student student = receiveDatas.get(position);

        // 2.2 获取对象属性

        holder.id = student.getId();

        final CheckBox cb = holder.cb;

        cb.setText(student.getName());// CheckBox显示内容

        // 2.3 对象属性监听

        cb.setOnClickListener(new OnClickListener() {



            @Override

            public void onClick(View v) {// 被点击

                if (cb.isChecked()) {// 被选中

                    map.put(position, true);

                    callBack.getSelectedCount(getSelectedCount());//个数监听

                    callBack.getSelectedItem(student);//被选项监听

                } else {// 未被选中

                    if (map.containsKey(position)) {// 选中项与否集合中包含此项

                        if (map.get(position) == true)

                            map.put(position, false);

                        callBack.getSelectedCount(getSelectedCount());//个数监听

                    }

                }



            }

        });

        // 2.4 设置对象属性

        cb.setChecked(map.get(position));

        return convertView;

    }



    /**

     * 被选中项的个数

     * 

     * @return

     */

    private int getSelectedCount() {

        int i = 0;

        for (Entry<Integer, Boolean> entry : map.entrySet()) {

            if (entry.getValue())

                i++;

        }

        return i;

    }



    public class ViewHolder {

        public int id;

        public CheckBox cb;

    }



    /**

     * 内部监听接口:向Activity暴露选择了多少项

     */

    public interface OnSelectedItemChanged {

        /**

         * 回调:处理被选中项个数

         * 

         * @param count

         */

        public void getSelectedCount(int count);

        

        public void getSelectedItem(Student student);



    }



    /**

     * 全选:改变状态+更新item界面+个数监听

     */

    public void selectAll() {

        for (int i = 0; i < map.size(); i++) {

            map.put(i, true);

        }

        notifyDataSetChanged();

        callBack.getSelectedCount(getSelectedCount());

    }



    /**

     * 全不选:改变状态+更新item界面+个数监听

     */

    public void disSelectAll() {

        for (int i = 0; i < map.size(); i++) {

            map.put(i, false);

        }

        notifyDataSetChanged();

        callBack.getSelectedCount(getSelectedCount());

    }



    /**

     * 反选:改变状态+更新item界面+个数监听

     */

    public void switchSelect() {

        for (int i = 0; i < map.size(); i++) {

            boolean select = map.get(i);

            map.put(i, !select);

        }

        notifyDataSetChanged();

        callBack.getSelectedCount(getSelectedCount());

    }



    /**

     * 当前被选中项

     * 

     * @return

     */

    public ArrayList<Student> currentSelect() {

        selectedItems.clear();

        for (int i = 0; i < map.size(); i++) {

            if (map.get(i))

                this.selectedItems.add(receiveDatas.get(i));

        }

        return this.selectedItems;

    }

}

4、adapter中实现了对item状态的监听、个数统计、全选/全不选/反选状态的切换,那么在Dialog中只需要简单的调用即可。废话少说,直接上码。

public class DialogActivity extends Activity {

    // 布局

    private Button selectAll, invert, sure, cancle;

    private TextView tv_count;

    private ListView layoutList;



    // 布局状态监听

    private boolean selectAllState;



    // 数据

    private DataController dataController;

    private ArrayList<Student> students;

    private ArrayList<Student> selectedStudent = new ArrayList<Student>();

    private StudentsApdater adapter;



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        // TODO Auto-generated method stub

        super.onCreate(savedInstanceState);



        setContentView(R.layout.dialog_activity);

        initData();

        initView();

    }



    /**

     * 初始化布局

     */

    private void initView() {

        selectAll = (Button) findViewById(R.id.dialogActivity_selectAll);

        invert = (Button) findViewById(R.id.dialogActivity_Invert);

        sure = (Button) findViewById(R.id.dialogActivity_sure);

        cancle = (Button) findViewById(R.id.dialogActivity_cancle);

        tv_count = (TextView) findViewById(R.id.dialogActivity_count);

        layoutList = (ListView) findViewById(R.id.dialogActivity_listView);

        adapter = new StudentsApdater(DialogActivity.this, students,

                new OnSelectedItemChanged() {



                    @Override

                    public void getSelectedCount(int count) {

                        tv_count.setText("总计:    " + count + " 次");

                    }



                    @Override

                    public void getSelectedItem(Student student) {

                        Toast.makeText(DialogActivity.this, student.getName(),

                                Toast.LENGTH_SHORT).show();

                    }

                });

        layoutList.setAdapter(adapter);

    }



    /**

     * 初始化数据

     */

    private void initData() {

        selectAllState = false;

        dataController = new DataController();

        if (dataController.getData() != null) {

            students = dataController.getData();

        } else {

            Toast.makeText(DialogActivity.this, "获取数据失败!", Toast.LENGTH_SHORT)

                    .show();

        }

    }



    /**

     * 被选项的获取

     * 

     * @return

     */

    public ArrayList<Student> getSelectedStudent() {

        return selectedStudent;

    }



    /**

     * 全选、反选、确定、取消 四个按钮的事件监听

     * 

     * @param view

     */

    public void doClick(View view) {

        Intent intent = null;

        switch (view.getId()) {

        case R.id.dialogActivity_selectAll:// 全选/全不选

            selectAllState=selectAllState==false?true:false;

            if (selectAllState) {

                adapter.selectAll();//通知变更状态

            } else

                adapter.disSelectAll();

            break;

        case R.id.dialogActivity_Invert:// 反选

            adapter.switchSelect();

            break;

        case R.id.dialogActivity_sure:// 确定

            selectedStudent = adapter.currentSelect();

            intent = new Intent();

            intent.putParcelableArrayListExtra("selectedStudents",

                    selectedStudent);// 将数据打包存入intent

            DialogActivity.this.setResult(Consts.RESULT_CODE_DIALOG2MAIN_SURE,

                    intent);

            DialogActivity.this.finish();

            break;

        case R.id.dialogActivity_cancle:// 取消

            intent = new Intent();

            DialogActivity.this.setResult(

                    Consts.RESULT_CODE_DIALOG2MAIN_CANCLE, intent);

            DialogActivity.this.finish();

            break;

        default:

            break;

        }

    }

}

5、获取到了被选中项的集合对象,那么只需要在调用Dialog的界面上处理得到的数据即可,还是继续上码。

public class MainActivity extends Activity {

    // 布局

    private Button btnDialog;

    private TextView tvShow;



    // 数据

    private DialogActivity dialogActivity;

    private ArrayList<Student> selectedStudent = null;



    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        initView();

        // initData();

    }



    private void initView() {

        dialogActivity = new DialogActivity();

        tvShow = (TextView) findViewById(R.id.tvShow);

        btnDialog = (Button) findViewById(R.id.btnDialog);

        btnDialog.setOnClickListener(new OnClickListener() {



            @Override

            public void onClick(View v) {

                startActivityForResult(new Intent(MainActivity.this,

                        DialogActivity.class), Consts.REQUEST_CODE_MAIN2DIALOG);

            }

        });

    }





    @Override

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == Consts.REQUEST_CODE_MAIN2DIALOG) {// 请求码为MainToDialog

            if (resultCode == Consts.RESULT_CODE_DIALOG2MAIN_CANCLE) {// 取消

                selectedStudent = null;

            } else if (resultCode == Consts.RESULT_CODE_DIALOG2MAIN_SURE) {

                selectedStudent = data

                        .getParcelableArrayListExtra("selectedStudents");

            }

        }

        handleSelectedData();

    }



    private void handleSelectedData() {

        tvShow.setText("");

        if (selectedStudent == null) {// 取消

            Toast.makeText(MainActivity.this, "你没有选择任何数据", Toast.LENGTH_SHORT)

                    .show();

        } else {// 确定

            if (selectedStudent.size() >= 1) {// 有选择

                StringBuilder sb = new StringBuilder();

                Student student = null;

                for (int i = 0; i < selectedStudent.size(); i++) {

                    student = selectedStudent.get(i);

                    sb.append(student.getName() + ",");

                }

                sb.deleteCharAt(sb.length() - 1);

                tvShow.setText(sb.toString());

            } else {// 无选择

                Toast.makeText(MainActivity.this, "你没有选择任何数据",

                        Toast.LENGTH_SHORT).show();

            }

        }

    }

}

6、总结,由于表达能力有限没能彻底解释清楚,回头有时间把全套源码奉上。

本文写的有不足之处,还望各位网友指点说明,共同进步,如需转载,请注明出处(PS:写博真的好费劲) http://www.cnblogs.com/android001/p/3625965.html

你可能感兴趣的:(ListView)