上面是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. kafka安装指导

    本篇博客主要讲解在虚拟机安装之后,从如下五个方面进行讲解kafka的安装过程. (1)如何配置虚拟机网络 (2)如何安装JDK (3)如何安装zookeeper (4)如何安装kafka (5)kaf ...

  2. css篇-页面布局-三栏布局

    页面布局 题目:假设高度已知,请写出三栏布局,其中左栏.右栏宽度各为300px,中间自适应. 1)浮动 2)绝对定位 3)Flexbox 4)表格布局 5)网格布局(CSS3的Grid布局) 代码: ...

  3. linux性能查看调优

    一 linux服务器性能查看1.1 cpu性能查看1.查看物理cpu个数:cat /proc/cpuinfo |grep "physical id"|sort|uniq|wc -l ...

  4. PHP中unset和null的比较

    起因 因为感兴趣于unset($var)和$var=null的区别,于是找了一个stackoverflow高分问题及答案,翻译以供参考. 注:以下的问题和答案翻译自http://stackoverfl ...

  5. aiohttp上报405: Method Not Allowed

    请求方式不对,修改为“POST”或者“GET” 可参考:https://blog.csdn.net/yiifaa/article/details/80928487

  6. c# DataTable第二行改为各列标题字段

    DataTable dt = ExcelHelper.ToDataTable(fileinfo.FilePath); //将datatable的第二行变为列标题字段 DataTable dt2 = n ...

  7. python使用SMTP发邮件时使用Cc(抄送)和Bcc(密送)

    SMTP发送邮件的时候,并没有特殊的通信语句告诉邮件服务器 谁是主送,谁是抄送/密送,这三个角色都是以同样的方式告诉邮件服务器的,然后重点在邮件内容里. 邮件内容分为头和体两部分(就像http),头部 ...

  8. 如何设置和使用MacOS上的Microsoft Office套件

    自30年前首次发布以来,Microsoft Office已成为全球最受欢迎的生产力套件之一.借助Word和Excel for Mac之类的程序,毫无疑问,MS Office套件在任何计算机上都是必须下 ...

  9. python判断文件的编码格式是否为UTF8 无BOM格式

    转自: https://www.cnblogs.com/ferraborghini/p/4951102.html https://www.cnblogs.com/Detector/p/8744992. ...

  10. Vue学习笔记【7】——Vue指令之v-model和双向数据绑定

    v-model是唯一可以实现双向数据绑定的vue指令 单向数据绑定:修改内存中的数据,页面上同步更改.v-bind <!-- v-bind 只能实现数据的单向绑定,从 M 自动绑定到 V, 无法 ...