Android ListView不响应OnItemClickListener解决办法


有时候,当ListView中的每一个item是自定义的View时,有可能会导致ListViewOnItemClickListenerlistener无法调用,请看如下情况:

 

如果你的自定义ListViewItem中有Button或者Checkable的子类控件的话,那么默认focus是交给了子控件,而 ListViewItem能被选中的基础是它能获取Focus,也就是说我们可以通过将ListViewItem中包含的所有控件的 focusable属性设置为false,这样的话ListViewItem自动获得了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.

注意:

还有一种情况也会导致OnItemClickListenerOnItemLongClickListener回调不会执行,那就是ListViewchild设置了onClickListeneronLongClickListener。我们可以通过源代码看出,在你调用setOnClickListener()方法后,它会调用setClickable(true),在onTouchEvent里面的实现如下: 

 

[java] view plaincopy

if (((viewFlags & CLICKABLE) == CLICKABLE ||  

                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {  

  

    // ....  

  

    return true;  

}  

当一个ViewonTouchEvent里面返回true后,ListView就不会正常接收到事件。

 

Listview 的朋友,可能会遇到这样的问题,当Listview的某一行有button存在时,无法弹出contextMenu;或者onItemClick onItemLongClick同时执行的等问题。

 

下面就一些常见问题疏理一下。

 1. ListView本身可不可以调用setOnClickListner() 

代码上可以,但是运行马上会丢出异常,所以是不可以拦截Listview本身的click事件。

 2.ListView.setOnItemClickListener设置的listener什么时候会被调用? 

当点击某行内容是会被调用,但是如果这行内容中包含ButtonImgButton等控件时就不会被调用,为什么以及怎么解决见后面。

3.ListView.setOnItemLongClickListener设置的listener什么时候被调用? 

当长按某一行时会被调用,而且在抬起之前就已经调用了。

4.onItemLongClick的调用后还会调用onItemClick吗?

 这个要根据onItemLongClick的返回值来决定。

 

lv.setOnItemClickListener(new OnItemLongClickListener() {              

public boolean onItemClick(AdapterView<?> parent, View view, int position, long id) {    

              System.out.println("Item LONG clicked. Position:" + position);           

              return false;          

      }

});

lv.setOnItemLongClickListener(new OnItemLongClickListener() {

    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {           

    System.out.println("Item LONG clicked. Position:" + position);          

    return false/true;  

    }

});

 

 如果返回false那么onItemClick仍然会被调用。而且是先调用onItemLongClick,然后调用onItemClick

 

 如果返回true那么click就会被吃掉,onItemClick就不会再被调用了。

 

5.监听onItemClick以及onItemLongClick影响弹出菜单吗? 

 

onItemClick不影响;onItemLongClick如果返回true那么就会吃掉click事件,导致菜单不能弹出。

 

6.如何让包含buttonitem也能弹出菜单,回调onItemClick以及onItemLongClick的监听器呢? 

需要设置Button属性:

android:focusable="false"  android:focusable="false" android:longClickable="true"  android:longClickable="true"否则无法收到

看不到你的adapter,怀疑是item里有个button或者是类似的抢占了itemOnClick事件

 

当我们使用listView嵌套button或者其它clickable控件时会出现listViewonitemClick事件不响应的问题。我们只需要在itemxml文件中的根布局中加上一句: android:descendantFocusability="blocksDescendants"  或在Button的布局中添加 android:focusable="false"   屏蔽item中抢夺focus的控件权限即可解决问题。

 

我们看到了一行代码定义的变量的意思是“当前View将屏蔽他所有子控件的Focus状态,即便这些子控件是可以Focus的”,其实这段话的意思就是这个变量代表着当前的View将不顾其子控件是否可以Focus自身接管了所有的Focus,通常默认能获得focus的控件有ButtonCheckable继承来的所有控件,这就意味着如果你的自定义ListViewItem中有Button或者Checkable的子类控件的话,那么默认focus是交给了子控件,而ListViewItem能被选中的基础是它能获取Focus,也就是说我们可以通过将ListViewItem中包含的所有控件的focusable属性设置为false,这样的话ListViewItem自动获得了Focus的权限,也就可以被选中了,也就会响应onItemClickListener中的onItemClick()方法,然而将ListViewItem Layout的子控件focusable属性设置为false有点繁琐,我们可以通过对Item Layout的根控件设置其android:descendantFocusability=blocksDescendant”即可,这样Item Layout就屏蔽了所有子控件获取Focus的权限,不需要针对Item Layout中的每一个控件重新设置focusable属性了,如此就可以顺利的响应onItemClickListener中的onItenClick()方法了

 

当我们使用listView嵌套button或者其它clickable控件时会出现listViewonitemClick事件不响应的问题。我们只需要在itemxml文件中的根布局中加上一句:

 

android:descendantFocusability="blocksDescendants"  

 

屏蔽item中抢夺focus的控件权限即可解决问题。

 

 在这里总结一下上面问题出现背景,item中有ImageButton,其余和平常使用listview一样的.当点击item时,onItemClickListener不起作用,ontouchListenermotionEvent.down消失了,事件只有点击item中的imagButton起作用。

    我们分析一下,当item出现了imageButton时,onItemClickListener不起作用,而在Touch中没有了down事件,首先说明onItemClickListener处理的和MotionEventdown事件有关,然后问题的关键是这个down事件去了哪里呢?

    经过排查当item中有Checkable类以及Button类控件的时候,item的焦点会被子项获得,此时这些子控件会将焦点获取到,所以常常当点击item时变化的是子控件,item本身的点击没有响应。从而导致onItemClickListener不起作用。

    已经得知了问题导致的原因就是因为item没有获得焦点,焦点被子项拿走了,那么怎么解决这类问题?本人认为处理的途径无非就是通过设置子项不能获得焦点,同时item要获得焦点。  

    这里采用的方法,要用到两个属性:

一:

android:focusable="false"

这个属性的具体介绍可以i看我上一篇文章,设置的目的在于使得某个控件不能获得焦点。

:

android:descendantFocusability="blocksDescendants"

这个属性用来设置子项焦点的处理先后顺序。

android:descendantFocusability

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

Must be one of the following constant values.

android:beforeFocusability      viewgroup在子项处理之前获得焦点

android:afterFocusability            viewGroup在子项处理之后获得焦点

android:blocksFocusability          viewGroup阻止子项获得焦点

 

上面就是说子项焦点能力,定义了viewgroup和它的子元素处理的关系,这关系是指当一个view在获得焦点的时候,值必须是下面的常量之一。

       那么,我们肯定imageButton不能获得焦点,因此添加ImageButton属性 focusable="false",同时我们希望item中子项不能获得焦点,所以要把给android:descendantFocusability="blocksDescendants"属性添加到imageButton的父元素即可,简单的做可以设置item的根节点上。

结:本次出现的onItemClickListener不能响应的原因是在item中有button类(子类)或者checkable类(子类)控件导致了item的焦点在子项的控件上,处理的办法就是将子项的控件焦点去掉,同时在itemxml设置阻止子项获得焦点的属性,即可解决尚需问题

   综述: 出现onItemClickListener不能响应,原因可能有多种,本人总结了有两种情况,一种是isEnable中返回值为false导致不能点击和选择,一种是因为item中有了checkable或者button类(子类)控件导致了item的焦点失去,从不能响应。因此需要仔细分析,问题导致的具体原因,才更好的解决问题。

 

你可能感兴趣的:(Android ListView不响应OnItemClickListener解决办法)