ListView CheckBox多选
来源:互联网 发布:自动化软件开发工程师 编辑:程序博客网 时间:2024/06/15 18:58
本实例可以直接嫁接与各类点餐APP上,当然你也可以发挥你的想象应用到其他项目之上,本实例主要实现的功能是,实现子类项目的单选、多选、全选和反选功能,点击确定时还能对应生成价格,下面结合代码对实例进行讲解。 主布局文件:
<?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" android:orientation="vertical"> <ListView android:id="@+id/lv_drink" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/ll_btns"></ListView> <LinearLayout android:id="@+id/ll_btns" android:layout_width="match_parent" android:layout_height="58dp" android:layout_alignParentBottom="true" android:orientation="horizontal"> <Button android:id="@+id/btn_commit" android:layout_width="wrap_content" android:layout_weight="1" android:layout_height="58dp" android:text="确定" /> <Button android:id="@+id/btn_select" android:layout_width="wrap_content" android:layout_weight="1" android:layout_height="58dp" android:text="点餐" /> <Button android:id="@+id/btn_select_all" android:layout_width="wrap_content" android:layout_weight="1" android:layout_height="58dp" android:text="全选" /> <Button android:id="@+id/btn_select_none" android:layout_width="wrap_content" android:layout_weight="1" android:layout_height="58dp" android:text="反选" /> </LinearLayout></RelativeLayout>
这里给每个Button的设置了layout_weight属性并赋值为1,这样所有的Button就可以平分整个屏幕宽度,这点在面试或项目中也是经常会遇到的,需要注意。
ListView的子项布局文件:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff" android:orientation="horizontal" > <CheckBox android:id="@+id/check_box" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="false" android:focusable="false" android:focusableInTouchMode="true" /> <ImageView android:id="@+id/food_imager" android:layout_width="50dp" android:layout_height="50dp" android:background="#ffffff" /> <TextView android:id="@+id/food_name" android:layout_width="100dp" android:layout_height="50dp" android:text="咖啡" android:gravity="center_vertical" android:layout_marginLeft="10dp" android:textSize="18sp" /> <TextView android:layout_width="wrap_content" android:layout_height="50dp" android:text="单价:RMB " android:paddingLeft="20dp" android:textSize="12sp" /> <TextView android:id="@+id/price" android:layout_width="wrap_content" android:layout_height="50dp" android:paddingRight="10dp" android:text="18" android:layout_marginLeft="20dp" android:textSize="18sp" /></LinearLayout>
采用线性布局,并设置了其orientation属性的值为horizontal即水平布局,包括一个CheckBox用于点餐选择(此处CheckBox的clickable属性设置成了false,意为不处理单击事件,交由父控件处理),一个ImageView用于图片展示,和三个TextView分别显示名称和价格。 为了方面数据操作,可以把属性封装成bean,此举也符合面向对象的思想,在开发中经常会用到,代码如下:
public class MyListAdapter extends BaseAdapter { // 填充数据的list private ArrayList<Drink> drinklist; // 用来控制CheckBox的选中状况 private static HashMap<Integer, Boolean> isSelected; // 上下文 private Context context; // 用来导入布局 private LayoutInflater inflater = null; private Boolean isShow = false; // 构造器 public MyListAdapter(ArrayList<Drink> list, Context context, Boolean isShow) { this.context = context; this.drinklist = list; inflater = LayoutInflater.from(context); isSelected = new HashMap<Integer, Boolean>(); this.isShow = isShow; // 初始化数据 initDatas(); } // 初始化isSelected的数据 private void initDatas() { for (int i = 0; i < drinklist.size(); i++) { getIsSelected().put(i, false); } } @Override public int getCount() { return drinklist.size(); } @Override public Object getItem(int position) { return drinklist.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { // 获得ViewHolder对象 holder = new ViewHolder(); // 导入布局并赋值给convertview convertView = inflater.inflate(R.layout.item, null); holder.imageView = (ImageView) convertView .findViewById(R.id.food_imager); holder.tv_name = (TextView) convertView.findViewById(R.id.food_name); holder.tv_price = (TextView) convertView.findViewById(R.id.price); holder.cb = (CheckBox) convertView.findViewById(R.id.check_box); // 为view设置标签 convertView.setTag(holder); } else { // 取出holder holder = (ViewHolder) convertView.getTag(); } // 获取数据 Drink food = drinklist.get(position); // 将数据填充到当前convertView的对应控件中 if (isShow) { holder.cb.setVisibility(View.VISIBLE); } else { holder.cb.setVisibility(View.GONE); } holder.imageView.setImageResource(food.drink_img); holder.tv_name.setText(food.drink_name); holder.tv_price.setText(food.drink_price); // 设置list中TextView的显示 // 根据isSelected来设置checkbox的选中状况 holder.cb.setChecked(getIsSelected().get(position)); return convertView; } public static HashMap<Integer, Boolean> getIsSelected() { return isSelected; } public static void setIsSelected(HashMap<Integer, Boolean> isSelected) { MyListAdapter.isSelected = isSelected; } public class ViewHolder { public TextView tv_name; public TextView tv_price; public ImageView imageView; public CheckBox cb; }}
对部分代码进行讲解:
这里创建了一个Map容器用以保存每个CheckBox的选择情况,当被选择时,Map的key存入CheckBox的序号,其Value存入true,反之,没有没选择Value存入false。为了方面操作这个Map容器,使用了getter和setter进行了封装。
InitDatas方法初始化了初始状态下的CheckBox都是未选择的。
构造方法传入了三个参数,分别是数据源、上下文对象、决定CheckBox和全选及反选按钮是否显示的标识。
- 四个必须覆写的方法上一节已经讲解它们的作用,这里就不再重复,为了提高运行效率,这里也使用了ViewHolder类。在getView方法中根据传入的isShow的布尔值决定是否显示CheckBox。 最后,MainActivity.java代码如下:(代码较长,分段讲解)
public class MainActivity extends Activity implements OnClickListener, OnItemClickListener { private ListView listView; private Button mCommitButton, mSelectButton, mSelectAllButton, mCancelAllButton; private ArrayList<Drink> drinks = new ArrayList<Drink>(); private MyListAdapter adapter; private CheckBox checkBox; private int checkNum; // 记录选中的条目数量 private ArrayList<String> list; private Boolean isShow = false; private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what == 1) { show(); } else if (msg.what == 0) { dismiss(); } }; }; private void show() { adapter = new MyListAdapter(drinks, getApplicationContext(), true); listView.setAdapter(adapter); isShow = true; mCancelAllButton.setVisibility(View.VISIBLE); mSelectAllButton.setVisibility(View.VISIBLE); } private void dismiss() { adapter = new MyListAdapter(drinks, getApplicationContext(), false); listView.setAdapter(adapter); isShow = false; mCancelAllButton.setVisibility(View.GONE); mSelectAllButton.setVisibility(View.GONE); }
为了方便统一处理监听事件,这里实现了OnClickListener单击监听和ListView的OnItemClickListener子项点击监听。此外,因为涉及到动态改变UI布局中控件的显示与否,这里采用了Handler机制,Handler机制一般用于更改主线程UI,在后面的章节还会详细讲解。
- 代码中有两个方法,一个是show,用于显示子项中的CheckBox(重新调用构造方法,第三个参数传入true)和主布局文件中的反选和全选按钮,dismiss方法则用于隐藏子项中的CheckBox(重新调用构造方法,第三个参数传入false)和主布局文件中的反选和全选按钮。
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); initView();// 初始化控件 initData();// 初始化数据 adapter = new MyListAdapter(drinks, getApplicationContext(), false); isShow = false; listView.setAdapter(adapter);}/** * 初始化控件 */public void initView() { View view = LayoutInflater.from(this).inflate(R.layout.item, null); checkBox = (CheckBox) view.findViewById(R.id.check_box); listView = (ListView) findViewById(R.id.lv_drink);// listview列表控件 mCommitButton = (Button) findViewById(R.id.btn_commit);// 确定按钮 list = new ArrayList<String>(); mSelectButton = (Button) findViewById(R.id.btn_select); mSelectAllButton = (Button) findViewById(R.id.btn_select_all); mCancelAllButton = (Button) findViewById(R.id.btn_select_none); mSelectAllButton.setOnClickListener(this); mCancelAllButton.setOnClickListener(this); if (isShow) { mSelectButton.setText("取消"); mCancelAllButton.setVisibility(View.VISIBLE); mSelectAllButton.setVisibility(View.VISIBLE); } else { mSelectButton.setText("点餐"); mCancelAllButton.setVisibility(View.GONE); mSelectAllButton.setVisibility(View.GONE); } mSelectButton.setOnClickListener(this); mCommitButton.setOnClickListener(this); listView.setOnItemClickListener(this);}/** * 初始化虚拟数据 */public void initData() { Class cls = R.drawable.class;// 反射 try { drinks.add(new Drink(cls.getDeclaredField("d1").getInt(null), "猕猴桃汁", "10")); drinks.add(new Drink(cls.getDeclaredField("d2").getInt(null), "橙汁", "12")); drinks.add(new Drink(cls.getDeclaredField("d3").getInt(null), "啤酒", "15")); drinks.add(new Drink(cls.getDeclaredField("d4").getInt(null), "葡萄汁", "10")); drinks.add(new Drink(cls.getDeclaredField("d5").getInt(null), "纯麦奶茶", "8")); drinks.add(new Drink(cls.getDeclaredField("d6").getInt(null), "薄荷汁", "10")); drinks.add(new Drink(cls.getDeclaredField("d7").getInt(null), "柠檬薄荷", "12")); drinks.add(new Drink(cls.getDeclaredField("d8").getInt(null), "椰子汁", "10")); drinks.add(new Drink(cls.getDeclaredField("d9").getInt(null), "珍珠奶茶", "9")); drinks.add(new Drink(cls.getDeclaredField("d10").getInt(null), "石榴汁", "10")); for (int i = 0; i < drinks.size(); i++) { list.add("data" + " " + i); } } catch (Exception e) { e.printStackTrace(); }}
这里主要有三个方法
onCreate方法,界面加载时首先会调用的方法,用于完成界面的初始化工作。这里初始化了适配器类MyListAdapter,这个类要传入三个参数,分别是数据源、上下文对象和控件显示标识,因为初始化时CheckBox、反选和全选按钮都不显示,所以这里传入false,最后调用setAdapter方法,设置适配器。
initView方法,为了控制子项中的控件,这里通过LayoutInflater.from(this).inflate(R.layout.item, null)方法获得了子项的布局文件,然后通过findViewById获得每一个控件对象。根据标识位isShow在初始化时控制第二个Button的text属性,并控制全选和反选按钮的显示与否。方法最后设置了三个控件的点击事件监听。
- initData方法,采用Java反射机制获取图片资源,然后将数据存储到list 集合中。
//按钮点击事件处理 @Override public void onClick(View v) { int mID = v.getId(); switch (mID) { case R.id.btn_commit: myPrice();// 计算总价并输出 break; case R.id.btn_select: whatToShow(); break; case R.id.btn_select_all: selectAll(); break; case R.id.btn_select_none: selectNone(); break; } } //全选方法 private void selectAll() { // 遍历list的长度,将MyAdapter中的map值全部设为true for (int i = 0; i < list.size(); i++) { MyListAdapter.getIsSelected().put(i, true); } // 数量设为list的长度 checkNum = list.size(); // 刷新listview和TextView的显示 adapter.notifyDataSetChanged(); } //决定第二个按钮显示 private void whatToShow() { if (isShow) { Message message = Message.obtain(); message.what = 0; handler.sendMessage(message); mSelectButton.setText("点餐"); } else { Message message = Message.obtain(); message.what = 1; handler.sendMessage(message); mSelectButton.setText("取消"); } } //反选方法 private void selectNone() { // 遍历list的长度,将MyAdapter中的map值全部设为true for (int i = 0; i < list.size(); i++) { MyListAdapter.getIsSelected().put(i, false); } // 数量设为list的长度 checkNum = list.size(); // 刷新listview和TextView的显示 adapter.notifyDataSetChanged(); } /** * 计算总价格的方法 */ public void myPrice() { HashMap<Integer, Boolean> map = MyListAdapter.getIsSelected(); String str = ""; int money = 0; for (int i = 0; i < map.size(); i++) { if (map.get(i)) { str += (i + " "); money += Integer.parseInt(drinks.get(i).drink_price); } } MyListAdapter.getIsSelected().get(""); Toast.makeText(getApplicationContext(), "已选中了" + str + "项,总价钱为:" + money, Toast.LENGTH_SHORT).show(); } /** * listview的item的选择的方法 */ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // 取得ViewHolder对象,这样就省去了通过层层的findViewById去实例化我们需要的cb实例的步骤 MyListAdapter.ViewHolder holder = (MyListAdapter.ViewHolder) view.getTag(); // 改变CheckBox的状态 holder.cb.toggle(); // 将CheckBox的选中状况记录下来 MyListAdapter.getIsSelected().put(position, holder.cb.isChecked()); }}
覆写了onClick方法,根据参数view并调用其getId的方法用来判断单击了哪一个按钮,然后进行相应的逻辑操作。
selectAll是全选的方法,通过遍历整个数据集合,将Map集合中的所有value改成true,并调用notifyDataSetChanged方法刷新ListView,selectNone则是反选的方法,同理遍历数据集合将Map中所有value的值改成false,并调用notifyDataSetChanged即可。
whatToShow方法,根据isShow的值判断是否显示CheckBox、反选和全选按钮,并动态这时mSelectButton的text属性。这里用到了Hanlder机制进行传值。
myPrice方法用于计算选择子项的总价格,通过getIsSelected方法获取是否选定的Map集合,然后进行数据集合的遍历,将选定的子项的价格求和即得到总的价格。
最后覆写了ListView的子项单击事件监听,将是否选定的结果记录到MyListAdapter.getIsSelected()方法获得的Map集合中。这里单击子项即可以选择CheckBox,因为在布局文件中将CheckBox的clickable属性设置成了false,由事件分发机制可知,子控件不消费点击事件,交由父控件(这里是ListView的子项)拦截消费单击监听,事件分发机制后面还会讲解。
- 这里传递数据的方式也可以选择接口回调的方式,对于回调方式,下一节会介绍,这里读者可以尝试自行实现。 运行实例如下:
单击点餐按钮后,点餐按钮本身会变成取消按钮,同时全选、反选按钮和CheckBox控件会显示出来,选择要点的饮料,点击确定按钮,会自动计算出选择饮料的总价格,通过Toast输出。
- ListView CheckBox多选
- listView中实现checkbox多选
- listview+checkbox
- ListView + CheckBox
- android中listView中实现checkbox多选
- listview + Viewholder + CheckBox 优化listview
- ListView中使用CheckBox
- android listview checkbox
- 带checkBox的ListView
- ListView 与 CheckBox
- 带CheckBox的ListView
- CheckBox in ListView
- CheckBox in WPF ListView
- listview中checkbox错乱
- 带CheckBox的ListView
- 含有CheckBox的ListView
- Android ListView与CheckBox
- ListView+CheckBox(一)
- 关于网络协议的一点学习
- Activity的生命周期
- HIGHGUI ERROR: V4L/V4L2: VIDIOC_S_CROP
- 从零开始用android studio
- krpano的调试
- ListView CheckBox多选
- 阿里云OS快速入门<上传本地图片>
- 让人眼花缭乱的视错觉,太酷炫了!
- Android 性能测试工具- GT
- spring mvc配置 + dbcp数据源+jdbcTemplate
- Sublime常用插件
- 欢迎使用CSDN-markdown编辑器
- IOCP服务器/客户端实现
- 通达OA麦枫自定义OA菜单的方法