listview在android开发中很地方都用到了,通常我们需要定制item里面的视图,就要重写adapter。而item中的控件根据需要来添加。但是如果出现了某些特定的item控件,就可能导致listview 的onItemClickListener不起作用。
下面是一个范例,说明这种情况。
首先还是先看代码:
布局xml文件如下:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
<ListView
android:id=
"@+id/lv_lv"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_weight=
"1.0"
android:dividerHeight=
"1px"
android:scrollbars=
"none"
/>
</LinearLayout>
|
item布局xml如下:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
View Code
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<ImageView
android:id=
"@+id/iv_photo"
android:layout_width=
"45dp"
android:layout_height=
"45dp"
/>
<TableLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_vertical"
android:layout_weight=
"1.0"
android:gravity=
"center_vertical"
>
<TableRow>
<TextView
android:id=
"@+id/tv_name"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_weight=
"1.0"
android:ellipsize=
"marquee"
android:marqueeRepeatLimit=
"marquee_forever"
android:singleLine=
"true"
android:text=
"xxx"
/>
</TableRow>
<TableRow>
<TextView
android:id=
"@+id/tv_phoneNum"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:ellipsize=
"marquee"
android:marqueeRepeatLimit=
"marquee_forever"
android:singleLine=
"true"
android:text=
"xxx"
/>
</TableRow>
</TableLayout>
<LinearLayout
android:layout_width=
"43dp"
android:layout_height=
"match_parent"
android:gravity=
"left|center_vertical"
>
<ImageButton
android:id=
"@+id/ib_call"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:src=
"@drawable/ic_launcher"
/>
</LinearLayout>
</LinearLayout>
|
注意里面有一个ImageButton。
在activity中设置listview的onItemClickListener,需要做的事情就是当点击item的时候出现log信息,代码如下:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
listView.setOnItemClickListener(
new
OnItemClickListener()
{
@Override
public
void
onItemClick(AdapterView<?> parent, View view,
int
position,
long
id)
{
// TODO Auto-generated method stub
Log.i(
"mm"
,
" onItemClick "
);
}
});
|
以及设置listview的onTouchListener,需要的事情只是当touch的时候MotionEvent的事件,代码如下:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
listView.setOnTouchListener(
new
OnTouchListener()
{
@Override
public
boolean
onTouch(View v, MotionEvent event)
{
// TODO Auto-generated method stub
if
(event.getAction() == MotionEvent.ACTION_DOWN)
{
Log.i(
"mm"
,
"MotionEvent.ACTION_DOWN"
);
}
else
if
(event.getAction() == MotionEvent.ACTION_UP)
{
Log.i(
"mm"
,
"MotionEvent.ACTION_UP"
);
}
else
if
(event.getAction() == MotionEvent.ACTION_MOVE)
{
Log.i(
"mm"
,
"MotionEvent.ACTION_MOVE"
);
}
return
false
;
}
});
|
在adapter中设置ImageButton的onClicklistener,需要做的事情只是打出log信息,代码如下:
01
02
03
04
05
06
07
08
09
10
|
holder.iv_call.setOnClickListener(
new
OnClickListener()
{
@Override
public
void
onClick(View v)
{
// TODO Auto-generated method stub
Log.i(
"mm"
,
"holder.iv_call.setOnClickListener "
);
}
});
|
好了,以上都做完了,接下来运行工程。出现界面以后,我们来使劲的点item位置(除了imageButton),
结果log中没有出现打印的
Log.i("mm", " onItemClick ");接下来拖动item看看touch事件
打出log如下:
01
02
03
04
|
11
-
07
08
:
42
:
27.793
: I/mm(
540
): MotionEvent.ACTION_MOVE
11
-
07
08
:
42
:
28.681
: I/mm(
540
): MotionEvent.ACTION_MOVE
11
-
07
08
:
42
:
28.832
: I/mm(
540
): MotionEvent.ACTION_MOVE
11
-
07
08
:
42
:
28.992
: I/mm(
540
): MotionEvent.ACTION_UP
|
大家可以看到没有action_down事件,也就是没有了点击事件,一个完整的touch是down--move--move--up,而这里没有了,这是为什么呢?
再点击imagButton,看看打印信息:
01
|
11
-
07
08
:
44
:
31.131
: I/mm(
540
): holder.iv_call.setOnClickListener
|
出现了我们期望的打印信息。
在这里总结一下上面问题出现背景,item中有ImageButton,其余和平常使用listview一样的,而点击了item时,onItemClickListener不起作用,onTouchListener没有了motionEvent.down事件,点击imagebutton有onclick事件。
我们分析一下,当item出现了imageButton时,onItemClickListener不起作用,而在Touch中没有了down事件,首先说明onItemClickListener处理的和MotionEvent的down事件有关,其次最重要的是这个down事件去了哪里呢?
因为当item中有Checkable类以及Button类控件的时候,item的焦点会被子项获得,此时这些子控件会将焦点获取到,所以常常当点击item时变化的是子控件,item本身的点击没有响应。从而导致onItemClickListener不起作用。
已经得知了问题导致的原因就是因为item没有获得焦点,焦点被子项拿走了,那么怎么解决这类问题,处理的途径无非就是通过设置子项不能获得焦点,同时item要获得焦点。
这里采用的方法,要用到两个属性:
一:
01
|
android:focusable=
"false"
|
二:
01
|
android:descendantFocusability=
"blocksDescendants"
|
这个属性用来设置子项焦点的处理先后顺序。
android:descendantFocusabilityDefines 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的根节点上。
以上作完后,我们在测试一下。
点击item,出现以下log:
01
02
03
|
11
-
07
09
:
48
:
19.671
: I/mm(
1077
): MotionEvent.ACTION_DOWN
11
-
07
09
:
48
:
19.751
: I/mm(
1077
): MotionEvent.ACTION_UP
11
-
07
09
:
48
:
19.952
: I/mm(
1077
): onItemClick
|
touch事件有了,ItemClick也有有了,
再次imageButton,出现以下log:
01
|
11
-
07
09
:
50
:
01.673
: I/mm(
1077
): holder.iv_call.setOnClickListener
|
说明点击ImageBUtton也获得点击事件。
以上完美的解决问题了。
总结:本次出现的onItemClickListener不能响应的原因是在item中有button类(子类)或者checkable类(子类)控件导致了item的焦点在子项的控件上,处理的办法就是将子项的控件焦点去掉,同时在item中xml设置阻止子项获得焦点的属性,即可解决尚需问题
综述: 出现onItemClickListener不能响应,原因可能有多种,本人总结了有两种情况,一种是isEnable中返回值为false导致不能点击和选择,一种是因为item中有了checkable或者button类(子类)控件导致了item的焦点失去,从不能响应。因此需要仔细分析,问题导致的具体原因,才更好的解决问题。
最后:感谢上一篇文章中给我给意见的同学。
欢迎大家访问我的博客: http://www.cnblogs.com/xilinch/archive/2012/11/07/2759265.html 欢迎转载,但请标明出处