Android 中自定义 ListView 无法响应 OnItemClickListener 中的 onItemClick 方法问题解决方案

在 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 = 0x20000;
/**
* This view will get focus only if none of its descendants want it.
*/
public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
/**
* This view will block any of its descendants from getting focus, even
* if they are focusable.
*/
public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;

/**     * This view will get focus before any of its descendants.     */

public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
/**     * This view will get focus only if none of its descendants want it.     */

public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
/**     * This view will block any of its descendants from getting focus, even     * if they are focusable.     */

public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;

我们看到了一行代码定义的变量的意思是“当前 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() 方法了。