ListView的item中有CheckBox焦点冲突

ListView的item点击无效是因为布局当中有Button或CheckBox,是这2个button抢到了焦点。

 

开发中很常见的一个问题,项目中的listview不仅仅是简单的文字,常常需要自己定义listview,自己的Adapter去继承BaseAdapter,在adapter中按照需求进行编写,问题就出现了,可能会发生点击每一个item的时候没有反应,无法获取的焦点。原因多半是由于在你自己定义的Item中存在诸如ImageButton,Button,CheckBox等子控件(也可以说是Button或者Checkable的子类控件),此时这些子控件会将焦点获取到,所以常常当点击item时变化的是子控件,item本身的点击没有响应。

   这时候就可以使用descendantFocusability来解决啦,API描述如下:

android:descendantFocusability

Defines the relationship between the ViewGroup and its descendantswhen looking for a View to take focus.

Must be one of the following constant values.

 

该属性是当一个为view获取焦点时,定义viewGroup和其子控件两者之间的关系。

属性的值有三种:

       beforeDescendants:viewgroup会优先其子类控件而获取到焦点

       afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点

       blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点

 

通常我们用到的是第三种,即在Item布局的根布局加上android:descendantFocusability=”blocksDescendants”的属性就好了,至此listview点击的灵异事件告一段落。心得:遇到不会不懂的地方除了网上查询资料之外,也可以多多去尝试每种属性的作用,多阅读官方文档(我始终觉得还是读原文的比翻译的理解的会更好)。

============================================================================

以上是一位博主针对ListView的Item焦点冲突进行的分析及解决方案。小编在此对Android的焦点问题进行一些拓展探究及提一下目前为止仍没有搞的很明白的问题。

其实上述问题不仅有博主这样的解决方案(在checkbox的父ViewGroup的属性中设置android:descendantFocusability="blocksDescendants"),另一个方案是在CheckBox组件的属性中设置android:focusable="false"。这样做也能解决问题,这也充分验证了Item点击失效就是因为CheckBox抢走了焦点所导致的。因为这两种做法实际上都是剥夺了CheckBox获取焦点的权利。

那么就可以看出,CheckBox的focusable属性默认是true的,而Item中的其它组件,如TextView、ImageView等的focusable属性默认是false的。也就是说其它这些组件默认情况下不能获取焦点。所以,我们如果想让一个View能够获取焦点就需要设置View.setFocusable(true);来“赋予权限”如果让这个View获取焦点,则需要追加设置View.requestFocus();来“提出申请”。

其实就“赋予权限”而言,我们看很多地方给出的不仅仅是android:focusable这个属性,还有个android:focusableInTouchMode这个属性。这两个属性都设置为true了。。

那么区别在哪里呢?在stackoverflow上已经有前辈问到了同样的问题http://stackoverflow.com/questions/23799064/what-is-the-difference-between-setfocusable-and-setfocusableintouchmode其实看方法名称就很明显,这里需要我们对InTouchMode的理解,直译成“触摸模式”。那么上面的两个属性就变成了:1.是否可以获得焦点;2.在触摸模式下是否可以获得焦点。“触摸模式”就是指“提出申请”(焦点)时的触发途径。这里有两个途径:1、通过手机的硬件按键触发(比如上、下、左、右);2、通过点击屏幕触发。InTouchMode就是指的第二个途径,所以,如果直接View.setFocusable()就是代表上面两个途径都包括在内(不管什么途径,都算)。

经过测试,小编总结了一下这两个属性的搭配用法:

当setFocusable=false时表示剥夺所有情况下View获得焦点的权利,但setFocusableInTouchMode=true能够使触摸模式下恢复获得焦点的权利;

当setFocusable=true时表示赋予所有情况下View获得焦点的权利,但setFocusableInTouchMode=false却不能够剥夺触摸模式下获得焦点的权利。

理解了上面两条规律后相信读者们以后就会知道怎样利用这两条属性了。


最后,小编还有一处迷糊的地方,希望明白的看客老爷们能够指点迷津:

在本文最初的problem中,ListView的Item中如果焦点被CheckBox抢走的话,会使CheckBox的父View点击失效,也就是无法响应OnClick事件。但是如果不是在ListView的Item中,同样的Item那样的布局,整个View是可以响应OnClick事件的。这是为什么呢?小编感觉可能是因为对“焦点”这个概念没有理解太透彻,所以搞不懂。希望大牛们指点一番。不胜感激!

你可能感兴趣的:(Android)