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

时间:2021-11-05 10:30:34

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

    照旧,先上图:

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

先做一下说明,第一张图是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