在 Android 软件设计与实现中我们通常都会使用到 ListView 这个控件,系统有一些预置的 Adapter 可以使用,例如 SimpleAdapter 和 ArrayAdapter,但是总是会有一些情况我们需要通过自定义 ListView 来实现一些效果,那么在这个时候,我们通常会碰到自定义 ListView 无法选中整个 ListViewItem 的情况,也就是无法响应 ListView 的 onItemClickListener 中的 onItemClick() 方法,究竟是为什么呢?我之前也在网上查过不少的资料,但是没有发现什么有价值的文章,有一些是建议在 Adapter 的 getView 方法中对自己需要响应单击事件的控件进行设置。但是最终的效果并不是特别理想,而且我认为这是一种取巧的方式,并不推荐。之后自己查看了一下 ViewGroup 的源码,发现了以下的一段常量声明:
/*** This view will get focus before any of its descendants.*/public static final int FOCUS_BEFORE_DESCENDANTS = 0×20000;/*** This view will get focus only if none of its descendants want it.*/public static final int FOCUS_AFTER_DESCENDANTS = 0×40000;/*** This view will block any of its descendants from getting focus, even if they are focusable.*/public static final int FOCUS_BLOCK_DESCENDANTS = 0×60000;/** * This view will get focus before any of its descendants. */public static final int FOCUS_BEFORE_DESCENDANTS = 0×20000;/** * This view will get focus only if none of its descendants want it. */public static final int FOCUS_AFTER_DESCENDANTS = 0×40000;/** * This view will block any of its descendants from getting focus, even if they are focusable. */public static final int FOCUS_BLOCK_DESCENDANTS = 0×60000;
我们看到了一行代码定义的变量的意思是“当前 View 将屏蔽他所有子控件的 Focus 状态,即便这些子控件是可以 Focus 的”,其实这段话的意思就是这个变量代表着当前的 View 将不顾其子控件是否可以 Focus 自身接管了所有的 Focus,通常默认能获得 Focus 的控件有 Button,Checkable 继承来的所有控件,这就意味着如果你的自定义 ListViewItem 中有 Button 或者 Checkable 的子类控件的话,那么默认 Focus 是交给了子控件,而 ListView的 Item 能被选中的基础是它能获取 Focus,也就是说我们可以通过将 ListView 中 Item 中包含的所有控件的 focusable 属性设置为 false,这 样的话ListView 的 Item自动获得了 Focus 的权限,也就可以被选中了,也就会响应 onItemClickListener 中的 onItemClick() 方法,然而将 ListView 的 Item Layout 的子控件 focusable 属性设置为 false 有点繁琐,我们可以通过对 Item Layout 的根控件设置其 android:descendantFocusability="blocksDescendant" 即可,这样 Item Layout 就屏蔽了所有子控件获取 Focus 的权限,不需要针对 Item Layout 中的每一个控件重新设置 focusable 属性了,如此就可以顺利的响应 onItemClickListener 中的 onItenClick() 方法了。