对TextVIew中特定字符串设定onTouchEvent方法_移动开发_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > 移动开发 > 对TextVIew中特定字符串设定onTouchEvent方法

对TextVIew中特定字符串设定onTouchEvent方法

 2014/4/14 12:07:03  丙丁  博客园  我要评论(0)
  • 摘要:上面是Iphone备忘录的图,笔者之前接到一个需求是实现点击文本框里的数字,弹出一个类似上图的按钮,显示出复制,要求是这个按钮的位置必须是根据你点击的位置进行定位(为什么这么说,是因为我们不可能把按钮放在你点击的地方那样显示效果不太好,一般都是在点击的位置再往上一定的尺寸)。关于这个需求,在脑海里速度分析下,就能找出几个点,首先,我们是要过滤TextView里的字符串,找出所有的数字,这个用正则很好实现,然后要给每串数字一个点击事件,这个可以通过SpannableString
  • 标签:方法 view touch 字符串

image

 

上面是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等指定特殊字符串与点击事件

发表评论
用户名: 匿名