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中所有文本都需要支持的功能,而超链接点击打开功能仅仅是超链接部分文本需要的。故我选择设置TextView的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()) { //长按事件,取消LinkMovementMethod处理,即不处理ClickableSpan点击事件
|
50
|
return false ;
|
51
|
}
|
52
|
link[ 0 ].onClick(widget);
|
53
|
Selection.removeSelection(buffer);
|
54
|
} else if (action == MotionEvent.ACTION_DOWN) {
|
55
|
Selection.setSelection(buffer, buffer.getSpanStart(link[ 0 ]), buffer.getSpanEnd(link[ 0 ]));
|
56
|
mLastActionDownTime = System.currentTimeMillis();
|
57
|
}
|
58
|
}
|
59
|
}
|
60
|
|
61
|
return false ;
|
62
|
}
|
63
|
}
|
上面的TextView::handleLinkMovementMethod()方法,其实就是从LinkMovementMethod::onTouchEvent()方法,稍微修改了下。主要就是两个逻辑:
1.ACTION_DOWN时,将点击位置的超链接选中;
2.ACTION_UP时,在非长按情况下,执行ClickableSpan的点击处理。
然后就完美解决了TextView的超链接点击打开和文本自由复制两个功能是互斥问题。
TextView中ClickableSpan与文本自由复制(TextIsSelectable)冲突问题相关推荐
- android TextView中ClickableSpan与文本自由复制(TextIsSelectable)冲突问题
上一篇文章解决了UrlSpan与文本中url链接识别和设置的问题,超链接可以正常显示了.但由于用户期望TextView中的文章内容可以自由复制,这个需求嘛实现起来就是设置下textView.setTe ...
- 给TextView中的部分文本添加链接的两种方式
方式一:在布局文件中给TextView制定autoLink属性,例如: <TextView android:id="@+id/tv2"android:layout_width ...
- android clickablespan listview,解决TextView中ClickableSpan点击事件
需求背景: 在TextView中包含局部可点击的链接,且改链接其他地方也是有相应的点击事件 其实需求比较合理,实现也应该不难,于是简单的demo如下: TextView content = (Text ...
- Android中TextView中添加的文本上下两行又重叠
如图显示的情况 代码如下: 我在网上查了查,网上只有显示EditText出现类似情况的,添加android:layerType="software"这句话,但必须得使用 API ...
- android textview import,android – textview中的镜像文本?
我很确定使用4.0之前的TextView是不可能的. 镜像自定义TextView并不难: package your.pkg; import android.content.Context; impor ...
- java textview多行_java-Android在textview中多个可点击的字符串
我正在创建一个小型 Android应用程序.我想在textview中显示一个文本,其中包含多个要单击的部分. (每个都应显示一些不同的消息) 最终,我设法找到了如何在一个textview中显示多个跨度 ...
- 网页导出pdf不完整_网页文本无法复制?学会这3个套路,一分钟帮你突破限制...
我们都是资源的搬运工,平时需要一些资料都会在网上查找,有时候当我们找到一些想要的内容,却发现复制不了,不是要收费就是被限制. 遇到这种情况怎么办?也许大多数人都会选择放弃,或者对照着内容手动打字.今天 ...
- android高仿微信聊天消息列表自由复制文字,双击查看文本内容
SelectTextHelper-高仿微信聊天消息列表自由复制文字,双击查看文本内容 掘金地址 github地址 SelectTextHelper打造一个全网最逼近微信聊天消息自由复制,双击查看文本内 ...
- android 系统复制,Android 复制文本内容到系统剪贴板(自由复制)
直接上代码:(对应的类:android.content.ClipboardManager) //获取剪贴板管理器: ClipboardManager cm =(ClipboardManager) ge ...
最新文章
- JVM调优:GC 参数
- 《Adobe After Effects CS6完全剖析》——动画:最重要的是关系
- c语言中x的n次方怎么表示_线性代数的本质及其在人工智能中的应用
- Spark Streaming之运行架构
- Adobe Illustrator的教程:使用渐变网格工具创建矢量插图
- 刚刚,李彦宏首谈Uber致命车祸,还给了一个很“特别”的评价
- 在后台Service中直接启动Activity
- 电大计算机网络本作业1,2017年最新电大计算机网络作业1-3答案.doc
- Ubuntu20.04安装 Redis 并配置 phpRedisAdmin
- 0成本教你打造属于自己的字体库
- FlashMX2004组件事件简单调试器
- 中科院-杨力祥视频教程	02课程
- 黑客帝国产业链调查:熊猫烧香作者一年赚千万
- mac关于 E45: ‘readonly‘ option is set (add ! to override)
- 大数据战略能不能打造第二个百度?
- 电脑视频加水印怎么加?
- 问题锦集 | 登入校园网乱码问题
- Android:rxjava简单实现原理(map/flatmap操作符)
- 压力应力测试软件,管道强度和应力计算软件
- 如何解除计算机方向键问题,笔记本键盘上下左右键怎么解锁_笔记本电脑的上下左右键被锁住了如何解决-win7之家...
热门文章
- 中小型研发团队架构实践十:应用监控怎么做?
- XEE漏洞任意文件读取
- 基于JAVA实现的塔防游戏
- python字符串索引局部变量_4. 列表一学完,Python 会一半,滚雪球学 Python【七日打卡】...
- 2022年江苏专转本计算机应用基础
- pymysql使用_使用pymysql的AWS Lambda与RDS
- Pygame实战:据说—这是一款还原度超高的植物大战僵尸游戏,你感受下......
- java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.gzl.cn.bean.Employee
- ssh页面中文乱码问题
- 信用卡消费挺进O2O市场