android TextView中ClickableSpan与文本自由复制(TextIsSelectable)冲突问题
上一篇文章解决了UrlSpan与文本中url链接识别和设置的问题,超链接可以正常显示了。但由于用户期望TextView中的文章内容可以自由复制,这个需求嘛实现起来就是设置下textView.setTextIsSelectable(true)就可以了。
天真的以为没啥问题,版本转测。立马出现一个严重问题,第一次点击超链接打开的网址与实际不符,第二次点击超链接才能打开正确的网址,或者说每次点击超链接文本打开的网址都是上一次点击区域内的超链接url。
贴TextView::onTouchEvent的源码
01
|
@Override
|
02
|
public boolean onTouchEvent(MotionEvent event) {
|
03
|
。。。
|
04
|
final boolean superResult = super .onTouchEvent(event);
|
05
|
if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
|
06
|
&& mText instanceof Spannable && mLayout != null ) {
|
07
|
boolean handled = false ;
|
08
|
09
|
if (mMovement != null ) {
|
10
|
handled |= mMovement.onTouchEvent( this , (Spannable) mText, event);
|
11
|
}
|
12
|
13
|
if (touchIsFinished && mLinksClickable && mAutoLinkMask != 0 && mTextIsSelectable) {
|
14
|
// The LinkMovementMethod which should handle taps on links has not been installed
|
15
|
// on non editable text that support text selection.
|
16
|
// We reproduce its behavior here to open links for these.
|
17
|
ClickableSpan[] links = ((Spannable) mText).getSpans(getSelectionStart(),
|
18
|
getSelectionEnd(), ClickableSpan. class );
|
19
|
20
|
if (links.length != 0 ) {
|
21
|
links[ 0 ].onClick( this );
|
22
|
handled = true ;
|
23
|
}
|
24
|
}
|
25
|
。。。
|
26
|
if (handled) {
|
27
|
return true ;
|
28
|
}
|
29
|
}
|
30
|
return superResult;
|
31
|
}
|
可以看到onTouchEvent()方法中涉及 ClickableSpan 处理的有两个关键点
关键点1.执行MovementMothed::onTouchEvent()方法(上面源码中蓝色部分)------mMovement.onTouchEvent(this, (Spannable) mText, event);
关键点2.上面源码中蓝色部分,在TextView的LinksClickable、AutoLink、TextIsSelectable属性都已设置情况下,获取当前选择区域内的ClickableSpan并执行其onClick()方法;
对于1,支持ClickableSpan使用的MovementMothed为LinkMovementMethod。而支持文本自由复制的MovementMothed为ArrowKeyMovementMethod。
设置了TextView的textIsSelectable属性后,TextView会自动设置器mMovement成员为ArrowKeyMovementMethod实例。此时文本才可以自由复制。也即上面关键点1中执行的是ArrowKeyMovementMethod::onTouchEvent()方法:长按时弹出复制、粘贴、选择菜单。
而我也正好设置了TextView的autoLink属性,故关键点2的if判断通过,但此时TextView中当前选择文本为记录的用户上次点击位置,故打开的链接也就是用户上次点击位置对应的链接url了,若用户上次点击位置没有超链接,就不会弹出浏览器打开链接的页面。
当然若去掉TextView的autoLink属性,用户点击超链接将不会产生任何操作。
总结:TextView的超链接点击打开和文本自由复制两个功能是互斥的,没办法同时支持。终于只要为啥百度贴吧 帖子中不能自由复制文本了。。。
两个功能都很重要,不可能删除哪一个。相比较之下文本自由复制功能是帖子内容TextView中所有文本都需要支持的功能,而超链接点击打开功能仅仅是超链接部分文本需要的。故我选择设置TextVie的textIsSelectable属性,即默认支持文本自由复制(此时不能修改mMovement为ArrowKeyMovementMethod外的其他MovementMothed,不然自由复制功能将会失效)。然后重写TextView::onTouchEvent()方法来支持超链接点击打开功能。具体如下:
01
|
public class CustomTextView extends TextView {
|
02
|
|
03
|
private long mLastActionDownTime = - 1 ;
|
04
|
public CustomTextView(Context context) {
|
05
|
super (context);
|
06
|
}
|
07
|
|
08
|
public CustomTextView(Context context, AttributeSet attrs) {
|
09
|
super (context, attrs);
|
10
|
}
|
11
|
12
|
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
|
13
|
super (context, attrs, defStyle);
|
14
|
}
|
15
|
16
|
@Override
|
17
|
public boolean onTouchEvent(MotionEvent event) {
|
18
|
CharSequence text = getText();
|
19
|
if (text != null && text instanceof Spannable) {
|
20
|
handleLinkMovementMethod( this , (Spannable)text, event);
|
21
|
}
|
22
|
23
|
return super .onTouchEvent(event);
|
24
|
}
|
25
|
|
26
|
private boolean handleLinkMovementMethod(TextView widget, Spannable buffer, MotionEvent event) {
|
27
|
int action = event.getAction();
|
28
|
29
|
if (action == MotionEvent.ACTION_UP ||
|
30
|
action == MotionEvent.ACTION_DOWN) {
|
31
|
int x = ( int ) event.getX();
|
32
|
int y = ( int ) event.getY();
|
33
|
34
|
x -= widget.getTotalPaddingLeft();
|
35
|
y -= widget.getTotalPaddingTop();
|
36
|
37
|
x += widget.getScrollX();
|
38
|
y += widget.getScrollY();
|
39
|
40
|
Layout layout = widget.getLayout();
|
41
|
int line = layout.getLineForVertical(y);
|
42
|
int off = layout.getOffsetForHorizontal(line, x);
|
43
|
44
|
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan. class );
|
45
|
46
|
if (link.length != 0 ) {
|
47
|
if (action == MotionEvent.ACTION_UP) {
|
48
|
long actionUpTime = System.currentTimeMillis();
|
49
|
if (actionUpTime - mLastActionDownTime > ViewConfiguration.getLongPressTimeout()) {
|
50
|
//长按事件,取消LinkMovementMethod处理,即不处理ClickableSpan点击事件
|
51
|
return false ;
|
52
|
}
|
53
|
link[ 0 ].onClick(widget);
|
54
|
Selection.removeSelection(buffer);
|
55
|
} else if (action == MotionEvent.ACTION_DOWN) {
|
56
|
Selection.setSelection(buffer, buffer.getSpanStart(link[ 0 ]), buffer.getSpanEnd(link[ 0 ]));
|
57
|
mLastActionDownTime = System.currentTimeMillis();
|
58
|
}
|
59
|
}
|
60
|
}
|
61
|
|
62
|
return false ;
|
63
|
}
|
64
|
}
|
上面的TextView::handleLinkMovementMethod()方法,其实就是从LinkMovementMethod::onTouchEvent()方法,稍微修改了下。主要就是两个逻辑:1.ACTION_DOWN时,将点击位置的超链接选中;2.ACTION_UP时,在非长按情况下,执行ClickableSpan的点击处理。
然后就完美解决了TextView的超链接点击打开和文本自由复制两个功能是互斥问题。
android TextView中ClickableSpan与文本自由复制(TextIsSelectable)冲突问题相关推荐
- TextView中ClickableSpan与文本自由复制(TextIsSelectable)冲突问题
上一篇文章解决了UrlSpan与文本中url链接识别和设置的问题,超链接可以正常显示了.但由于用户期望TextView中的文章内容可以自由复制,这个需求嘛实现起来就是设置下textView.setTe ...
- android textview import,android – textview中的镜像文本?
我很确定使用4.0之前的TextView是不可能的. 镜像自定义TextView并不难: package your.pkg; import android.content.Context; impor ...
- Android TextView中设定个别文字字体显示格式
Android TextView中设定个别文字字体显示格式 文章分类:移动开发 用Html来格式化字符,例如要实现如下的显示: "这只是一个测试字符串,测试黑体字.斜体字.下划线.红色字的显示." 可 ...
- Android TextView中图文混排设置行间距导致高度不一致问题解决
Android TextView中图文混排设置行间距导致高度不一致问题解决 参考文章: (1)Android TextView中图文混排设置行间距导致高度不一致问题解决 (2)https://www. ...
- android textview显示表情,在Android TextView中显示表情符号/情感图标
我在Android TextView中显示表情符号图标时遇到一些问题 首先,我在这里找到了Unicode表情符号图标列表:http : //www.easyapns.com/category/just ...
- android clickablespan listview,解决TextView中ClickableSpan点击事件
需求背景: 在TextView中包含局部可点击的链接,且改链接其他地方也是有相应的点击事件 其实需求比较合理,实现也应该不难,于是简单的demo如下: TextView content = (Text ...
- 给TextView中的部分文本添加链接的两种方式
方式一:在布局文件中给TextView制定autoLink属性,例如: <TextView android:id="@+id/tv2"android:layout_width ...
- Android TextView中文字通过SpannableString来设置超链接、颜色、字体等属性
在Android中,TextView是我们最常用的用来显示文本的控件. 一般情况下,TextView中的文本都是一个样式.那么如何对于TextView中各个部分的文本来设置字体,大小,颜色,样式,以及 ...
- android TextView中文字通过SpannableString设置属性
2019独角兽企业重金招聘Python工程师标准>>> 在Android中,TextView是我们最常用的用来显示文本的控件. 一般情况下,TextView中的文本都是一个样式.那么 ...
最新文章
- 对抗性分割损失素描着色
- linux expect 自动交互 执行命令 超时 不完整 中断 解决方法
- c语言变长数组_2018级C语言大作业 - 祖玛
- linux qt应用程序全屏,QT中MDI应用程序中更改子窗口大小或是全屏显示子窗口的方法...
- [NOIP2003] 提高组 洛谷P1041 传染病控制
- mysql pdo insert_PDO数据库操作类——插入数据的实现
- 个人风格就是一种品牌
- 微软、英特尔和高盛牵头成立供应链安全工作组
- 学习C语言的入门程序
- c语言实现万年历程序
- 分频器+计数器+数码管显示VHDL
- ARCore 之路:如何创建一个 ARCore 程序?
- linux iptable 使用指南
- 运维守护神——数十万线上机器的守护【门神】
- 【docker】docker重新加载nginx配置
- h5 加载完成_开业通知朋友圈怎么写?新店开业宣传H5
- 2017网易笔试矩阵快速幂
- f1c100s kernel调试记录
- 家庭网络搭建_家庭网络
- InceptionV3代码解析
热门文章
- 为什么要使用变调夹 简单易懂版
- java中excel导入图片_java POI实现向Excel中插入图片
- Nansen复盘加密巨头自救:如何阻止百亿多米诺倾塌
- 音乐知识讲座-音名与唱名
- 大咖说:蜂窝车联网(C-V2X)技术发展、应用及展望
- 《Android移动应用基础教程》(Android Studio)(第二版)黑马教程 课后题答案第2章 Android常见界面布局
- [SaaS研究] SaaS在中国 / 中国的Salesforce / 阿里巴巴 / 阿里软件 [ 转 ]
- 向量夹角顺时针或逆时针,交叉口向左拐向右拐的问题
- 实战篇:SEK之买卖方向成交量分析
- 人品计算器代码Android,Android 人品计算器案例