上面是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. 基于MFC的Media Player播放器的制作介绍

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. 因为这次多媒体课程设计做一个基于MFC的播放器,因为本人实力太菜,需要播放音乐或视频文件时候,自己写不出解码 函数,所以准备使用第三方多媒 ...

  2. spark sql数据源--hive

    使用的是idea编辑器 spark sql从hive中读取数据的步骤:1.引入hive的jar包 2.将hive-site.xml放到resource下 3.spark sql声明对hive的支持 案 ...

  3. kafka的简介

    1. kafka是一个分布式消息队列.具有高性能.持久化.多副本备份.横向扩展能力.生产者往队列里写消息,消费者从队列里取消息进行业务逻辑.一般在架构设计中起到解耦.削峰.异步处理的作用. 1.1 b ...

  4. leetcode.位运算.136只出现一次的元素-Java

    1. 具体题目 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.找出那个只出现了一次的元素. 说明:你的算法应该具有线性时间复杂度. 你可以不使用额外空间来实现吗? 示例 1 ...

  5. tushare下载安装教程与版本更新步骤

    使用前提 安装Python 安装pandas:pip install pandas 安装lxml:pip install lxml 下载安装 方式1:pip install tushare,如果安装网 ...

  6. Smokeping分享

    Somkeping master端搭建过程 服务端/master端 一. 搭好环境,安装依赖包(1)yum -y install httpd fping echoping curl  rrdtool ...

  7. Java-技术专区-虚拟机系列-内存模型(JMM)

           Java8内存模型—永久代(PermGen)和元空间(Metaspace) 一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部 ...

  8. pthread_create()的一个错误示例

    //pthread_create()函数的错误示例 //新建线程同时传入线程号.线程号总和和消息 #include <stdio.h> #include <pthread.h> ...

  9. linux 7 安装KVM

    首先,在安装GUI的linux 7系统下,安装KVM 执行命令 #yum install qemu-kvm qemu-kvm-tools virt-manager libvirt virt-insta ...

  10. redis实现分布式锁需要考虑的因素以及可重入锁实现

    死锁 错误例子 解决方式  防止死锁 通过设置超时时间  不要使用setnx key   expire 20  不能保证原子性 如果setnx程序就挂了 没有执行expire就死锁了  reidis2 ...