有时候,当ListView中的每一个item是自定义的View时,有可能会导致ListView的OnItemClickListener的listener无法调用,请看如下情况:
如果你的自定义ListViewItem中有Button或者Checkable的子类控件的话,那么默认focus是交给了子控件,而 ListView的Item能被选中的基础是它能获取Focus,也就是说我们可以通过将ListView中Item中包含的所有控件的 focusable属性设置为false,这样的话ListView的Item自动获得了Focus的权限,也就可以被选中了。
我们可以通过对Item Layout的根控件设置其android:descendantFocusability="blocksDescendants"即可,这样Item Layout就屏蔽了所有子控件获取Focus的权限,不需要针对Item Layout中的每一个控件重新设置focusable属性了,如此就可以顺利的响应onItemClickListener中的onItemClick()方法了。
总结:
原因:
ListView中的Item内部的View获得了焦点,如Button, Checkbox等。
解决办法:
不要让ListView中的Item内部的View获得焦点就OK了,这样做:android:descendantFocusability="blocksDescendants"
public static final int descendantFocusability
Defines the relationship between the ViewGroup and its descendants when looking for a View to take focus.
Constant | Value | Description |
beforeDescendants | 0 | The ViewGroup will get focus before any of its descendants. |
afterDescendants | 1 | The ViewGroup will get focus only if none of its descendants want it. |
blocksDescendants | 2 | The ViewGroup will block its descendants from receiving focus. |
注意:
还有一种情况也会导致OnItemClickListener或OnItemLongClickListener回调不会执行,那就是ListView的child设置了onClickListener或onLongClickListener。我们可以通过源代码看出,在你调用setOnClickListener()方法后,它会调用setClickable(true),在onTouchEvent里面的实现如下:
- /**
- * Register a callback to be invoked when this view is clicked. If this view is not
- * clickable, it becomes clickable.
- *
- * @param l The callback that will run
- *
- * @see #setClickable(boolean)
- */
- public void setOnClickListener(OnClickListener l) {
- if (!isClickable()) {
- setClickable(true);
- }
- getListenerInfo().mOnClickListener = l;
- }
- if (((viewFlags & CLICKABLE) == CLICKABLE ||
- (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
- // ....
- return true;
- }
当一个View在onTouchEvent里面返回true后,ListView就不会正常接收到事件。