Android初级基础知识复习(十) —— 列表类视图

列表类视图

基本适配器BaseAdapter

Android提供了一种适应性更强的基本适配器BaseAdapter,该适配器允许开发者在别的代码文件中进行逻辑 处理,大大提高了代码的可读性和可维护性。
从BaseAdapter派生的数据适配器主要实现下面3个方法。

  1. 构造函数:指定适配器需要处理的数据集合。
  2. getCount:获取数据项的个数。
  3. getView:获取每项的展示视图,并对每项的内部控件进行业务处理。

下面以Spinner控件为载体,演示如何操作BaseAdapter,具体的编码分为3步:
步骤01 编写列表项的布局文件。
步骤02 写个新的适配器继承BaseAdapter,实现对列表项视图的获取与操作。
步骤03 在页面代码中构造该适配器,并应用于Spinner对象。

列表视图ListView

ListView允许在页面图下拉框在页面上只显示一行上分行展示相似的数据界面,如新闻列表、商品列表、书籍列表等,方便用户逐行浏览与操作。
在这里插入图片描述
另外,ListView实现了3个与适配器相关的方法:

  1. setAdapter:设置列表项的数据适配器,适配器一般继承BaseAdapter。
  2. setOnItemClickListener:设置列表项的点击事件监听器OnItemClickListener。
  3. setOnItemLongClickListener:设置列表项的长按事件监听器OnItemLongClickListener。

光看这些文字会觉得ListView是个加强版的Spinner,不但可以直接在页面上展示列表,而且能设置分 隔线与点击监听器。事实上,ListView很令人头痛,使用过程中经常出现意想不到的状况,比如分隔线就容易出状况。

根据分隔线测试代码的演示结果,笔者总结了一下,大概有以下5种情况:
(1)代码中的setDivider方法只能设置具体的图片不能设置颜色,即使把颜色值转为ColorDrawable 也不行。在布局文件中可对divider属性直接指定颜色值
(2)divider属性设置为@null时不能再设置dividerHeight属性为大于0的数值,因为这样一来最后一项就不会完全显示,底部有一部分被掩盖了。原因是列表高度为wrap_content时,系统已按照没有分隔线的情况计算列表高度,此时dividerHeight占用了n-1块空白分隔区域,最后一项被挤到背影里面去了。
(3)代码中要设置分隔线,务必先调用setDivider方法再调用setDividerHeight方法。如果先调用 setDividerHeight再调用setDivider,分隔线高度就会变成分隔图片的高度,而不是setDividerHeight设置的高度。布局文件不存在先后顺序问题。
(4)显示列表底部的分隔线是有条件的,即当前ListView的高度不能为wrap_content,否则就算把 footerDividersEnabled设置为true、调用setFooterDividersEnabled方法设置为true这条底部的分隔线也不会出现。除非把列表的高度设置为match_parent或设置足够高,才会显示底部的分隔线,调整列表高度后的具体效果。
(5)列表顶部的分隔线就更难办了,ListView不会显示顶部的分隔线。无论是headerDividersEnabled属 性还是setHeaderDividersEnabled方法都没有作用,而且调整列表高度也没什么用,非常难以解决。

既然底部和顶部的分隔线令人这般头痛,不如直接扔掉,另外想想别的办法。使用padding即可解决这 个问题。首先给ListView设置背景图片,然后分别设置paddingTop与paddingBottom,接下来顶部和底部就会出现两个背景图的padding。

上面第3点和第5点已经明确是Android的bug,较真的读者不必把时间浪费在上面。这不是设置问题, 也不是方法调用问题,而是SDK的代码逻辑问题,详述如下:
(1)关于setDivider方法与setDividerHeight方法的先后顺序关系,参见下面的setDivider方法源码,问题 在于if条件,这里“divider != null”的条件不准确,应当改为“divider!=null &&mDividerHeight<=0”,如果已经 指定分隔线的高度,就不使用分隔图片的高度了。
(2)关于无法显示顶部的分隔线问题,可查看ListView源码的dispatchDraw方法,这里把问题代码贴出 来了,具体如下:
bounds.top = bottom; // 注意这里的设置有问题,边界上方已经是列表项的底部了
bounds.bottom = bottom + dividerHeight;
drawDivider(canvas, bounds, i);
可以看到分隔线固定在该项底部,如果在顶部看到分隔线,那才是怪事。正确的写法是对顶部的分隔 线做分支处理,如果需要展示顶部的分隔线,就给bounds.bottom赋值为child.getTop(),给bounds.top赋值为 child.getTop()-dividerHeight。 幸好ListView的这些毛病都是小问题,不影响将其发扬光大。

在实战中,ListView表现得还不是很完美,有3个地方要特别注意:
(1)如果ListView下面还有其他控件,就要将ListView的高度设为0dp,权重设为1,确保列表视图扩展到所有剩余页面如果ListView的高度设置为wrap_content,系统就只预留一行高度,如此一来只有第一行显示,这显然不是我们所期望的。
(2)给列表项注册上下文菜单也不容易,如果按照之前对上下文菜单的操作,长按列表项时App就会异常退出。这是因为上下文菜单的长按事件列表项的长按监听器OnItemLongClickListener相互影响,使得程序陷入了死循环。最后的处理办法是要把两种长按事件阻隔开,即列表项长按事件处理完毕后才触发上下文菜单事件,打开上下文菜单之前得清空列表项的长按事件
(3)如果列表项包含EditText、Button(包括ImageButton、CheckBox等按钮)等控件,此时点击列表项不会响应点击监听器OnItemClickListener。罪魁祸首还是焦点抢占问题,之前介绍EditText时提到页面会自动弹出软键盘,就是EditText抢占焦点造成的。同理,列表项中如果存在EditText和Button,这些子控件也会抢占列表项的焦点,使得点击操作被视为对EditText和Button的点击(无论点击处是否落在EditText和 Button的范围内),而不是列表项的点击。解决办法是给列表项布局文件的根节点加上 descendantFocusability属性,并声明在列表项范围内剥夺子控件的抢占权利,具体的属性设置代码如下: android:descendantFocusability=“blocksDescendants”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值