上面是Iphone备忘录的图,笔者之前接到一个需求是实现点击文本框里的数字,弹出一个类似上图的按钮,显示出复制,要求是这个按钮的位置必须是根据你点击的位置进行定位(为什么这么说,是因为我们不可能把按钮放在你点击的地方那样显示效果不太好,一般都是在点击的位置再往上一定的尺寸)。关于这个需求,在脑海里速度分析下,就能找出几个点,首先,我们是要过滤TextView里的字符串,找出所有的数字,这个用正则很好实现,然后要给每串数字一个点击事件,这个可以通过SpannableString.setSpan和TextView.setMovementMethod(MovementMethod movement)来实现,实现起来大概是这样。

private void init() {
tvMain.setMovementMethod(LinkMovementMethod.getInstance());
SpannableString s = new SpannableString(CONTENT);
filterNumber(s);
tvMain.setText(s);
} private static final String REG = "\\d+"; public class TextClickableSpan extends ClickableSpan {
private String text; public TextClickableSpan(String text) {
this.text = text;
} @Override
public void onClick(View view) {
//do something
        }
}
private void filterNumber(Spannable s) {
Matcher m = Pattern.compile(REG).matcher(s.toString());
while (m.find()) {
String text = m.group();
TextClickableSpan span = new TextClickableSpan(text);
s.setSpan(span,m.start(),m.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}

当我想在onClick()里做处理的时候,我发现我无法得到我当前点击的位置,这让我想起来一个叫做onTouchEvent的方法,可惜ClickSpan里没这方法。于是我就自定义了一个TouchableSpan类

public abstract class TouchableSpan extends CharacterStyle implements UpdateAppearance {
@Override
public void updateDrawState(TextPaint tp) {
tp.setColor(tp.linkColor);
tp.setUnderlineText(true);
} public abstract void onActionUp(View view,MotionEvent event); }

有两个方法,第一个方法是我直接从ClickableSpan里抄过来的,很明显,这是用来设置样式的,分别是颜色和下划线。第二个方法是onActionUp(View view,MotionEvent event);这个事我自定义的,用来响应我们点击松手时的事件,在这里,我传入了一个MotionEvent,这样我们就能获得到点击的坐标了。但是又出现一个问题,LinkMovementMethod里只会调用ClickableSpan的onClick()方法。所以我最后又写了一个TouchableMovementMethod继承LinkMovementMethod类

public class TouchableMovementMethod extends LinkMovementMethod {

    private static TouchableMovementMethod sInstance;

    public static TouchableMovementMethod getInstance() {
if (sInstance == null) {
sInstance = new TouchableMovementMethod();
}
return sInstance;
} 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);
TouchableSpan [] touchSpans = buffer.getSpans(off, off, TouchableSpan.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]));
} return true;
} else if (touchSpans.length != 0) {
if (action == MotionEvent.ACTION_UP) {
touchSpans[0].onClick(widget,event);
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(touchSpans[0]),
buffer.getSpanEnd(touchSpans[0]));
} return true;
} else {
Selection.removeSelection(buffer);
}
} return false;
}
}

代码很简单,我只是重写了onTouchEvent方法(这个方法是LinkMovementMethod 本来就有的),我稍作了一些修改,让他既可以支持原有的ClickableSpan,又可以支持我们的TouchableSpan。这样就能很好的实现无法获得点击坐标的难题了,,

相关博文:自定义可点击的ImageSpan并在TextView中内置“View“

解析TextView中的URL等指定特殊字符串与点击事件

对TextVIew中特定字符串设定onTouchEvent方法的更多相关文章

  1. java中两字符串比较--compareTo方法

    java.lang.String.compareTo() 方法比较两个字符串的字典,比较是基于字符串中的每个字符的Unicode值 String n1 = "1"; String ...

  2. JavaScript中去除字符串空格的方法

    语法 string.trim() 参数值 无 返回值 类型:string 描述:返回移除头尾空格的字符串 技术细节 JavaScript版本: ECMAScript 5 去除字符串左右两端的空格,在v ...

  3. C# 从 UTF-8 流中读取字符串的正确方法

    我们下面的代码是从一个流 stream 中读取 UTF-8 编码的字符串.我们可以先考虑一下其中存在的潜在问题. string ReadString(Stream stream) { var sb = ...

  4. MyEclipse如何查找指定工程下所有或指定文件中特定字符串并且可进行批量替换

    查找操作步骤:(1)在myEclipse里菜单选择-Search-Search(快捷键:ctrl+h);(2)在弹出对话框中选File Search选项,然后在第一个文本框中输入“要查找的字符串”(为 ...

  5. python中的字符串内置方法小结

    #!/usr/local/bin/python3 # -*- coding:utf-8 -*- ''' name="my wife is mahongyan" ---------- ...

  6. linux查看日志中特定字符串以及前后信息内容命令

    在项目实施过程中,我们经常会查看日志,更是经常会根据某些特地字符串去查找日志内容. 下面就是日志查找命令: 1.查询字符串命令: cat fileName|grep '要查找的字符串' 实例:cat ...

  7. 在SQL中 给字符串补0方法

    --第一种方法SELECT RIGHT('00000'+CAST(ID AS nvarchar(50)),5) FROM dbo.TableName --左边补0,如 00001,00039 SELE ...

  8. C#中判断字符串相等的方法

    可以使用如下方式: 1. String.Compare(str1, str2) == 0  或者  str1.CompareTo(str2) == 0 2. str1.Equals(str2)  或者 ...

  9. C#替换文件中特定字符串,按照原来的编码格式保存

    private void button1_Click(object sender, EventArgs e) { var txt1 = "E:\\Temp\\local"; str ...

随机推荐

  1. vue.js实现点击后动态添加class及删除同级class

    最近使用vue需要实现一个点餐选择商品规格的页面,需要通过vue动态的给被点击的元素添加class名字,使其变色,其他的删除class.如图: 开始在网上找了许多办法发现不是太好用,最后找到一个发现还 ...

  2. mac 密码重置

    首先请开机或重新启动系统,在电脑刚启动时,请按下键盘上的 command+S 组合键不动, 接下来会在屏幕上看到一串串的命令字符显示,当进入安全模式以后,会看到 一个 root 开始的命令行输入端口. ...

  3. 备份一下alias喽

    # 每次grep都显示出行号示出行号 alias grep="grep -n" # grep反向选择并显示行号显示行号 alias vgrep="grep -n -v&q ...

  4. linux - sftp, scp, rz, sz(文件传输命令)

    1. sftp Secure Ftp 是一个基于SSH安全协议的文件传输管理工具.由于它是基于SSH的,会在传输过程中对用户的密码.数据等敏感信息进行加密,因此可以有效的防止用户信息在传输的过程中被窃 ...

  5. JS window对象 userAgent 返回用户代理头的字符串表示(就是包括浏览器版本信息等的字符串) 语法 navigator.userAgent

    userAgent 返回用户代理头的字符串表示(就是包括浏览器版本信息等的字符串) 语法 navigator.userAgent 几种浏览的user_agent.,像360的兼容模式用的是IE.极速模 ...

  6. BiLSTM介绍

    https://www.jiqizhixin.com/articles/2018-10-24-13 (机器之心)

  7. 浅谈HTTP与其工作流程

    一.什么是HTTP协议 HTTP协议(Hyper Text Transfer Protocol)翻译过来是超文本传输协议,也是一种restful风格的协议,在web开发和APP接口开发都很常用. HT ...

  8. 基于Libpcap实现一个网络数据包嗅探器

    基本功能就是来捕获所有流经本网卡的数据包. 实现流程: 查找网络设备 打开网络设备 查找设备信息 输入过滤规则 编译输入规则 设置输入规则 开始捕获数据包 调用数据包分析模块 输出MAC,IP,协议以 ...

  9. Java中如何实现序列化,有什么意义?

    序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化.可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间.序列化是为了解决对象流读写操作时可能引发的问题(如果不进行序 ...

  10. Python排序功能进阶

    sorted和sort() li = [9, 1, 8, 2, 7, 3, 6, 4, 5] s_li = sorted(li) print ('Sorted Variable: \t', s_li) ...