热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

1、首先明确要实现的功能:一个Dialog包含有ListView,每个item都是一个CheckBox。此Dialog可实现对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 receiveDatas;// 接收的数据 ,private Map map;// 保存被选中与否的状态的集合, private ArrayList selectedItems;// 被选中项的集合。 那么下面来解决第一个问题,对每一个item上的CheckBox状态切换的监听:在item对其布局上的控件CheckBox进行初始化后,立即设置监听,一旦被选中或被取消则变更选中状态。接着解决第二个问题,既然是外部的某项指令改变了ListView内部item选中状态,那么BaseAdapter需要提供一个public方法供外部调用而此方法专门用于修改item选中状态与否的修改+item界面更新+选中的item个数的监听。第三个问题就不做过多解释了,当map中的某项的状态为true时将与之对应的对象添加到selectedItems集合中。最后第四个问题,我们需要一个内部的回调接口用于监听每次状态变更,然后调用回调函数,将其展现在前台的Dialog中。

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

public class StudentsApdater extends BaseAdapter {
    private ArrayList receiveDatas;// 接收的数据
    private OnSelectedItemChanged callBack;// 内部接口:监听选中项的个数(随着item被点击而改变)
    private LayoutInflater inflater;

    private Map map;// 保存被选中与否的状态的集合
    private ArrayList selectedItems;// 被选中项的集合

    /**
     * 构造方法
     * 
     * @param context
     * @param receiveDatas
     */
    public StudentsApdater(Context context, ArrayList receiveDatas,
            OnSelectedItemChanged callBack) {
        inflater = LayoutInflater.from(context);
        this.receiveDatas = receiveDatas;
        this.callBack = callBack;

        // 初始化被选中项
        map = new HashMap();
        for (int i = 0; i ) {
            map.put(i, false);
        }
        // 初始化被选中项的集合
        selectedItems = new ArrayList();
    }

    /**
     * 数据的设置
     * 
     * @param receiveDatas
     */
    public void setDatas(ArrayList 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 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.put(i, true);
        }
        notifyDataSetChanged();
        callBack.getSelectedCount(getSelectedCount());
    }

    /**
     * 全不选:改变状态+更新item界面+个数监听
     */
    public void disSelectAll() {
        for (int i = 0; i ) {
            map.put(i, false);
        }
        notifyDataSetChanged();
        callBack.getSelectedCount(getSelectedCount());
    }

    /**
     * 反选:改变状态+更新item界面+个数监听
     */
    public void switchSelect() {
        for (int i = 0; i ) {
            boolean select = map.get(i);
            map.put(i, !select);
        }
        notifyDataSetChanged();
        callBack.getSelectedCount(getSelectedCount());
    }

    /**
     * 当前被选中项
     * 
     * @return
     */
    public ArrayList currentSelect() {
        selectedItems.clear();
        for (int i = 0; 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 students;
    private ArrayList selectedStudent = new ArrayList();
    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 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 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 ) {
                    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


推荐阅读
  • 尽管我们尽最大努力,任何软件开发过程中都难免会出现缺陷。为了更有效地提升对支持部门的协助与支撑,本文探讨了多种策略和最佳实践,旨在通过改进沟通、增强培训和支持流程来减少这些缺陷的影响,并提高整体服务质量和客户满意度。 ... [详细]
  • 深入解析 Android 中 EditText 的 getLayoutParams 方法及其代码应用实例 ... [详细]
  • 本文介绍如何在 Android 中自定义加载对话框 CustomProgressDialog,包括自定义 View 类和 XML 布局文件的详细步骤。 ... [详细]
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
  • 在探讨C语言编程文本编辑器的最佳选择与专业推荐时,本文将引导读者构建一个基础的文本编辑器程序。该程序不仅能够打开并显示文本文件的内容及其路径,还集成了菜单和工具栏功能,为用户提供更加便捷的操作体验。通过本案例的学习,读者可以深入了解文本编辑器的核心实现机制。 ... [详细]
  • 在Delphi7下要制作系统托盘,只能制作一个比较简单的系统托盘,因为ShellAPI文件定义的TNotifyIconData结构体是比较早的版本。定义如下:1234 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • 本文介绍了一种利用Dom4j库和JFileChooser组件在Java中实现XML文件自定义路径导出的方法。通过创建一个Document对象并设置根元素,结合JFileChooser选择目标路径,实现了灵活的XML文件导出功能。具体步骤包括初始化Document对象、构建XML结构以及使用JFileChooser选择保存路径,确保用户能够方便地将生成的XML文件保存到指定位置。 ... [详细]
  • 优化升级版数据采集与赋值方法,专为前文内容设计
    在前一篇文章中,方法的局限性主要体现在需要传递参数,并且参数数量受限。当页面布局与所需参数不匹配时,该方法将无法正常工作。为此,我们推出了优化升级版1.1,旨在解决这些问题并提高灵活性和适用性。 ... [详细]
  • 实验九:使用SharedPreferences存储简单数据
    本实验旨在帮助学生理解和掌握使用SharedPreferences存储和读取简单数据的方法,包括程序参数和用户选项。 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • 深入解析Struts、Spring与Hibernate三大框架的面试要点与技巧 ... [详细]
  • 在Android开发中,当TextView的高度固定且内容超出时,可以通过设置其内置的滚动条属性来实现垂直滚动功能。具体来说,可以通过配置`android:scrollbars="vertical"`来启用垂直滚动,确保用户能够查看完整的内容。此外,为了优化用户体验,建议结合`setMovementMethod(ScrollerMovementMethod.getInstance())`方法,使滚动操作更加流畅和自然。 ... [详细]
  • 在 Kubernetes 中,Pod 的调度通常由集群的自动调度策略决定,这些策略主要关注资源充足性和负载均衡。然而,在某些场景下,用户可能需要更精细地控制 Pod 的调度行为,例如将特定的服务(如 GitLab)部署到特定节点上,以提高性能或满足特定需求。本文深入解析了 Kubernetes 的亲和性调度机制,并探讨了多种优化策略,帮助用户实现更高效、更灵活的资源管理。 ... [详细]
  • 在Python中,是否可以通过使用Tkinter或ttk库创建一个具有自动换行功能的多行标签,并使其宽度能够随着父容器的变化而动态调整?例如,在调整NotePad窗口宽度时,实现类似记事本的自动换行效果。这种功能在设计需要显示长文本的对话框时非常有用,确保文本内容能够完整且美观地展示。 ... [详细]
author-avatar
爱中华爱美丽
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有