zoukankan      html  css  js  c++  java
  • [基础控件]---自定义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

  • 相关阅读:
    前端面试题精选
    闭包、作用域、THIS、OOP
    Ubuntu,debian一键安装Mariadb
    两条命令实现nodejs快速安装
    HTML 5的革新——语义化标签section和article的区别
    uni-app之uni.showToast()image路径问题
    vue-cli4配置文件别名
    蓝湖使用方法
    Node组件——Express简介
    程序员最深情的告白——《致对象》
  • 原文地址:https://www.cnblogs.com/android001/p/3625965.html
Copyright © 2011-2022 走看看