1、首先明确要实现的功能:一个Dialog包含有ListView,每个item都是一个CheckBox。此Dialog可实现对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