zoukankan      html  css  js  c++  java
  • 对TextVIew中特定字符串设定onTouchEvent方法

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

  • 相关阅读:
    activity启动模式
    Android自定义view:折线图(附带动画效果)
    支付宝开发接口 Multiple dex files define Lcom/ta/utdid2/device/UTDevice
    android 开发中应用到的单例模式
    新浪微博分享错误代码 10014
    android Model与View解耦的一个简单方式
    android studio 新建项目导入到Coding远程仓库git
    一起学习MVC(2)数据库设计
    ASP.NET MVC :MVC页面验证与授权
    ASP.net:水晶报表的5种表格设计模式
  • 原文地址:https://www.cnblogs.com/luction/p/3663599.html
Copyright © 2011-2022 走看看