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()方法了。

Android中自定义ListView无法响应OnItemClickListener中的onItemClick方法问题解决方案》有29个想法

    1. lishali 文章作者

      设置Block只是会让OnItemClickListener成功监听到OnItemClick事件而已,应该不会影响到Item中Button的点击的,不知道你碰到的是什么问题?如果方便的话,可以将问题的详细情况描述一下,这样好分析一些。

      回复
  1. wjd

    这文章是你自己写的还是转的,如果是自己写的,你觉得里的逻辑对吗?“当前View将屏蔽他所有子控件的Focus状态,即便这些子控件是可以Focus的”,其实这段话的意思就是这个变量代表着当前的View将不顾其子控件是否可以Focus自身接管了所有的Focus“,你说这句话的意思不就是layout先于laoyout的子控件拿到focus,怎么后面又搞句 “这就意味着如果你的自定义ListViewItem中有Button或者Checkable的子类控件的话,那么默认focus是交给了子控件”,完全对不上号,下面的人还一个劲的评论看懂了…是把属性设成false后,自已的程序正常了,就觉得看懂了吧.把button的focusable设成false后,item是能获得click事件,同时单击button,button也能得到响应,这个又是什么原因呢,button连焦点都被它的父控件给截获了,怎么还能响应click事件呢?你能把这个解释清楚吗?

    回复
    1. lishali 文章作者

      这位兄台,不用着急,首先这篇文章一定是我写的,这个不容置疑。
      其次我的逻辑是对的,在Layout中存在Button和Checkable的子控件时确实会将OnItemClickListener给截获,导致无法响应onItemClickListener方法,将Layout中所有控件的focusable设置为false也能让item响应OnItemClickListener,与button自己能响应onClick本身就不冲突,你任何一个点击行为都会被dispatch的,首先就会判断item中子控件是否是可以点击的,如果可以的话而且设置了onClickListener的话,那么一定会响应onClick方法,至于将android:descendantFocusability=”blocksDescendant”设置给item的layout会保证OnItemClickListener正常使用是绝对没有问题的,请分清楚我在讲的问题是focusable而不是clickable,在Android中焦点本身就和可点击没有一个必然的联系,请确认这个问题。

      回复
  2. zyx

    呵呵 楼主你好··看到文章了··但是我也按照你的方式加上去了··但是还是无妨响应OnItemClickListener···里面的ImageButton是可以的···求指点:Q308711822 谢谢楼主哦 呵呵·

    回复
  3. Sam

    楼主你好, 我按照你的方式加上去了, 可是还是没反应. 我的情况是,点击Menu,会弹出一个PoPWindow,里面有三个Tab, 每个Tab里面装有Gridview, GridView里面的item点击事件没反应. GridView里面没有放其他的Button或者Checkable子控件. 我觉得应该也是焦点问题. 但是不知道为什么改了focusable属性后,还是不行. 求指点

    回复
    1. lishali 文章作者

      先确定一下是否是PopWindow的问题,例如先在PopWindow的三个Tab中不放GridView,放个Button试试能否获取点击事件,然后一步一步地试,然后将GridView放到Tab中去看看,确定问题了之后应该就能找到解决方法了

      回复
  4. ha

    我也按照您的方法寫了,但還是沒有反應
    我用了繼承CursorAdapter的自寫Adapter
    我還有使用到一個spinner,這會影響嗎?????

    回复
  5. Pingback引用通告: android,listview,自定义列表,adapter

  6. Pingback引用通告: listview问题总结 - 移动开发教程 - 开发者

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据