http://my.oschina.net/djone/blog/145057
一、前提和解决
做了个界面,在listview的itemview里 要@,要超链接,要话题跳转等等等。
用ClickableSpan实现了textview的点击跳转,之后发现listview的OnItemClickListener不响应,给textview的focusable设置为false,或者listview的descendantFocusability为blocksDescendants都不管使。
百度后发现了Terry_龙的代码看着很科学,可是复制粘贴后发现还是不行,继续百度找到一个求助贴,接着跳转到了一个英文网站。。介绍完艰辛旅程,下面是正解:
/* ********************** 解决方法 ************************ */
1、抄完Terry_龙的代码
1
2
3
4
5
6
7
8
9
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
public
class
TextViewFixTouchConsume
extends
TextView {
boolean
dontConsumeNonUrlClicks =
true
;
boolean
linkHit;
public
TextViewFixTouchConsume(Context context) {
super
(context);
}
public
TextViewFixTouchConsume(Context context, AttributeSet attrs) {
super
(context, attrs);
}
public
TextViewFixTouchConsume(Context context, AttributeSet attrs,
int
defStyle) {
super
(context, attrs, defStyle);
}
@Override
public
boolean
onTouchEvent(MotionEvent event) {
linkHit =
false
;
boolean
res =
super
.onTouchEvent(event);
if
(dontConsumeNonUrlClicks)
return
linkHit;
return
res;
}
public
static
class
LocalLinkMovementMethod
extends
LinkMovementMethod{
static
LocalLinkMovementMethod sInstance;
public
static
LocalLinkMovementMethod getInstance() {
if
(sInstance ==
null
)
sInstance =
new
LocalLinkMovementMethod();
return
sInstance;
}
@Override
public
boolean
onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int
action = event.getAction();
if
(action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int
x = (
int
) event.getX();
int
y = (
int
) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int
line = layout.getLineForVertical(y);
int
off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.
class
);
if
(link.length !=
0
) {
if
(action == MotionEvent.ACTION_UP) {
link[
0
].onClick(widget);
}
else
if
(action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[
0
]),
buffer.getSpanEnd(link[
0
]));
}
if
(widget
instanceof
TextViewFixTouchConsume){
((TextViewFixTouchConsume) widget).linkHit =
true
;
}
return
true
;
}
else
{
Selection.removeSelection(buffer);
Touch.onTouchEvent(widget, buffer, event);
return
false
;
}
}
return
Touch.onTouchEvent(widget, buffer, event);
}
}
}
|
2、在自定义的TextView多写一个
1
2
3
4
|
@Override
public
boolean
hasFocusable() {
return
false
;
}
|
3、完工, 随后你就可以使用
setMovementMethod(TextViewFixTouchConsume.LocalLinkMovementMethod.getInstance());
这样即给TextView增加点击效果,又不让其占用Item的点击焦点。类似微博的@ 、表情、链接等。
/* ********************** 解决方法到此结束 ************************ */
二、原理 (来自 英文网页):
当调用textview的setMovementMethod 或者 setKeyListener, TextView 自动修改它的属性:
setFocusable(true);
1、这也就是说你手动设置的focusable被覆盖掉了,也就需要我们覆写hasFocusable方法,使其始终返回false。
2、覆写hasFocusable之后listview的OnItemClick已经可以响应,以有限的大脑容量我以为自定义的LinkMovementMethod可以不要了,可惜注释掉之后发现ClickableSpan不工作了。。。
三、已知Bug:
在上面找到的求助贴里楼主问:使用这个解决方案后每次滑动都会调用onItemLongClick事件,我又测试了一下把长按事件加在TextView上,发现一样会在滑动时被激活。就是说使用这个方法后长按事件就别用了。