界面分为两部分:ListView和线性布局的两个按钮
利用ListView显示列表
这里的布局具有技巧性;ListView的高度=窗口高度-线性布局的高度
那么给ListView设置重要级别layout_weight为1 默认的是0(0是最高的,往后数字越大重要性越低)
这样的话线性布局的重要性就最高了,于是优先布局线性布局,然后将剩余的控件给ListView
注意ListView里的条目界面只有一个复选框!!!
把数据绑定到每个条目里面。注意item是一个布局,其里面的checkBox是一个控件
还要给线性布局添加一个背景图片。
注意
1 拖动的时候变颜色。ListView有缓存的颜色,所以将其缓存的颜色设置为透明
2 ListView选择了最前面的两个,但是下一页的前两个也被选中了。适配器对象内部会缓存哪些显示控件(checkBox)被选中了。
当我们再翻到了第二页的时候ListView,要显示控件自然会再次调用适配器对象的getView()方法返回条目的视图对象。所以在翻到第二页
的时候显示的是缓存里面的视图对象。所以次视图对象还是第一页的视图对象,只是对象里面的数字(电话号码)发生了变化
所以也呈现出了被选中的状态。总结:翻到下一页的时候,显示控件是ListView缓存里的,但是数据是从Map里取出来的新数据。
所以:应该根据数据的被选择状态来判断复选框是否被选中,而不是根据显示控件的选择状态来判断复选框被选中
解决办法:重写simpleAdapter 重写simpleAdapter里面的getView()对象
复选框的被点击的级别很高,所以在点击的时候实际是点了复选框,而不是条目 所以不能让复选框可以被点击(但是这样的话也就部可以被选中了,然后用代码来使复选框可以
被选中)
老师说的按照缓存来解释是不太合理的
其实没有那么复杂:简单地来说我们的手段就是将数据(电话号码)绑定到一个视图(复选框),数据和视图构成了ListView的每一个条目(即item)。可以这么理解:在ListView注册
适配器的一瞬间,完成了数据到复选框的绑定。选中了第一页(屏幕)的第一和第二个复选框,但是拉倒第二页的时候,第二页的相同位置依然被选中了。因为:在翻到第二页的时
候要显示该页的画面,所以要重绘界面即ListView调用了适配器的getView()方法。但是,适配器是按照每页中复选框的ID来记录哪些视图(复选框)被选中,而不是按照所有视图(
复选框)中复选框的ID来记录,所以重绘的时候,选择的依然是上页的复选框在上页的ID而决定本页显示复选框在本页的ID,所以在相同位置的复选框被现实了。于是我们要重写
getView()方法。
所以:应该根据数据(电话号码)的被选择状态来判断复选框是否被选中,而不是根据复选框的选择状态来判断复选框被选中
利用private HashMap<Integer, Boolean> datacheckstate = null;//记录数据(电话号码)的被选状态,key为记录的ID,value为状态。初始时都是为被选中的。
position指的是map在list中的位置。
checkbox的级别很高,点击条目的时候实际是点击了checkbox!!!
所以让checkbox不可以被点击,不可以被触摸,不可以获得焦点。这样的话checkbox就永远不可以被选中了
于是再采用代码的方式,让checkbox被选中。即在ItemClickListener里面
CheckBox checkBox = (CheckBox)view.findViewById(R.id.checkBox);
checkBox.toggle();//对复选框的状态进行切换
datacheckstate.put(rowid, checkBox.isChecked());
最后一句其实也是利用了复选框的状态决定了数据(电话号码)的被选状态
在添加和删除黑名单以后要重绘界面
问题起源:
将电话号码与复选框绑定在一起,利用ListView控件
达到的目的——将复选框被选中的电话号码删除。
但是没有想像的那么简单,会出现的意外状况
1 选中第一页的第2,3个复选框,当翻到第二页的时候其相同位置也被选中
解决思路:绝不能依靠复选框的被选中来删除黑名单号码(原因见上面分析)
所以根据数据的被选择状态决定复选框是否被选中
所以要从条目的点击着手处理!!!!!!!!!条目是数据与视图的结合点。不能简单地从复选框入手。
解决办法:自定义SimpleAdapter类,重写getView()方法。而且借用了外部的全局的balckNumberIsCheckedMap保存了电话号码的状态,初始时均未被选中。
重写SimpleAdapter类的getView()方法主要目的是利用数据的状态来决定CheckBox的状态,初始时CheckBox均未被选中。那么数据的状态是在哪里发生变化的呢?条目被点击的时
候切换CheckBox的状态,且注意在条目被点击的时候——因为在点击条目的时候可以知道那个数据被点击了即代码:
HashMap<String,Object> itemHashMap=(HashMap<String, Object>) lv.getItemAtPosition(position);//得到ListView被点击条目所绑定的HashMap
也就知道了被绑定的电话号码的ID。
利用了一个HashMap<Integer, Boolean> balckNumberIsCheckedMap来保存每个号码的状态,初始时都为false。
2 紧接着带来的问题是,我们在点击条目的时候因为复选框的级别很高,所以实际点击的是复选框
即无法实现条目的点击事件。这样就很糟糕了,因为我们的数据是绑定在ListView的每一个条目
上的,无法处理条目的监听事件,于是就没有什么意义了。
于是在布局文件中使复选框不可以被点击,不可以被触摸,不可以获得焦点!!!
核心思想:利用ListView条目的每次点击来切换CheckBox的状态,然后将CheckBox的状态作为电话号码的 状态!!!!将其号码及其状态存放回到HashMap<Integer, Boolean>
balckNumberIsCheckedMap中
每点击一下就会切换CheckBox的状态!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
关于通过ListView将数据绑定到复选框的问题的总结
问题来源:
1 选中第一页的第2,3个复选框,当翻到第二页的时候其相同位置也被选中
解决思路:绝不能依靠复选框的被选中来删除黑名单号码(原因见上面分析),而依靠哪个数据被选中来删除黑名单.那么怎么知道这个数据是否被选中呢?就是通过
CheckBox的被选状态来提示用户的。所以说CheckBox只是起到一个显示作用!!
解决办法:自定义SimpleAdapter类,重写getView()方法。而且借用了外部的全局的balckNumberIsCheckedMap保存了每个电话号码的状态,初始时均未被选中。
重写getView()方法的目的:
(1)实现数据的绑定checkBox.setText(blacknumber);//这里就是绑定的实质。把这个电话号码绑定到了ListView的这个checkbox上
(2)为CheckBox赋予初始状态(初始状态均为未被选中)
boolean isChecked=balckNumberIsCheckedMap.get(id);
checkBox.setChecked(isChecked);
2 通过实现对于条目点击事件的监听,我们在点击条目的时候可知道是背后的那条数据被点击
即HashMap<String,Object> itemHashMap=(HashMap<String, Object>) lv.getItemAtPosition(position);于是就可以修改此号码在balckNumberIsCheckedMap中的状态
从而用此状态来决定复选框CheckBox的状态,这样的话点击几个条目去实现删除的时候遍历balckNumberIsCheckedMap查看哪些号码被选中,把选中的删除即可。
这样带来了第二个问题:点击条目的时候,其实没有真正地点击到条目,而是点击了复选框CheckBox,因为复选框的优先级很高。
解决办法:在布局文件中使复选框不可以被点击,不可以被触摸,不可以获得焦点!!!于是在点击条目的时候就真的是在点击条目了!!!!!!!!
于是可以这样处理条目点击事件:
(1) 在点击的时候切换复选框状态checkBox.toggle();每点击条目都会切换此状态;然后得到复选框现在的状态即boolean itemIsCheck=checkBox.isChecked();
(2) 得到当前被点击电话号码即HashMap<String,Object> itemHashMap=(HashMap<String, Object>) lv.getItemAtPosition(position);
(3) 得到号码的ID即int blackNumberId=(Integer) itemHashMap.get("id");
(4) 然后修改此号码在balckNumberIsCheckedMap中的状态即balckNumberIsCheckedMap.put(blackNumberId, itemIsCheck);
这样就实现了形式与内容的统一,复选框的状态发生了变化,而且正确体现了实际情况。
核心代码如下:
checkBox.toggle();
boolean itemIsCheck=checkBox.isChecked();//得到checkBox目前的状态
HashMap<String,Object> itemHashMap=(HashMap<String, Object>) lv.getItemAtPosition(position);//得到ListView被点击条目所绑定的HashMap
int blackNumberId=(Integer) itemHashMap.get("id");
balckNumberIsCheckedMap.put(blackNumberId, itemIsCheck);
当我们执行删除的时候:其实就是去HashMap<Integer, Boolean> balckNumberIsCheckedMap看哪些数据被选中了,若被选中就删除它们。