Android TextView设置自动识别的超链接字体颜色,及自身点击事件无响应的解决办法

前言

我们在给TextView设置超链接的时候,可能最简单的,Android已经给出了一个非常的简单的做法就是:
在xml中设置:


android:autoLink="web"  

或者

//sp为SpannableString
Linkify.addLinks(sp, Linkify.WEB_URLS);

如何设置超链接颜色

上边如果设置,就可以完成基本功能,但是安装在不同的手机上,超链接的颜色都会不同,比如vivo的一个机子上是黑色的,显示的样式也不一样!

所以,这里只能使用URLSpan手动去匹配,并设置颜色:

        //注意:不要在xml配置android:autoLink属性
        SpannableString sp = new SpannableString(str);
        //这句很重要,也可以添加自定义正则表达式
        Linkify.addLinks(sp, Linkify.WEB_URLS);
        //主要是获取span的位置
        URLSpan[] spans = sp.getSpans(0, str.length(), URLSpan.class);
        //这里可以用过循环处理就可以动态实现文本颜色的差别化了
        //设置高亮样式一
        for (URLSpan span : spans) {
            sp.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.base_blue)), sp.getSpanStart(span), sp.getSpanEnd(span), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        //SpannableString对象设置给TextView
        mTv.setText(sp);
        //设置TextView可点击
        mTv.setMovementMethod(LinkMovementMethod.getInstance());

问题,textview点击事件失效

为什么会出现这样的问题,是因为LinkMovementMethod中onTouchEvent(MotionEvent event),在ACTION_UP事件中,返回了true,表示这里已经消费了up事件,那么自然不会再响应它的点击事件!
所以,这里的解决方案:
我在stackoverflow上找到一个回答:listview-textview-with-linkmovementmethod-makes-list-item-unclickable

public class LinkTextView extends android.support.v7.widget.AppCompatTextView {

    boolean dontConsumeNonUrlClicks = true;
    boolean linkHit;

    public LinkTextView(Context context) {
        super(context);
    }

    public LinkTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public LinkTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        linkHit = false;
        boolean res = super.onTouchEvent(event);

        if (dontConsumeNonUrlClicks)
            return linkHit;
        return res;

    }

    public static class LocalLinkMovementMethod extends LinkMovementMethod {
        static LocalLinkMovementMethod sInstance;


        public static LocalLinkMovementMethod getInstance() {
            if (sInstance == null)
                sInstance = new LocalLinkMovementMethod();

            return sInstance;
        }

        @Override
        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);

                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]));
                    }

                    if (widget instanceof LinkTextView) {
                        ((LinkTextView) widget).linkHit = true;
                    }
                    return true;
                } else {
                    Selection.removeSelection(buffer);
                    Touch.onTouchEvent(widget, buffer, event);
                    return false;
                }
            }
            return Touch.onTouchEvent(widget, buffer, event);
        }
    }
}

然后在使用的时候:

//设置TextView可点击,并且调用自定义的LinkMovementMethod,不是url,返回false,否则会消费掉点击事件
mTv.setMovementMethod(LinkTextView.LocalLinkMovementMethod.getInstance());

首先我们自定义一个TextView,定义一个布尔值,是否点击了超链接,然后我们继承LinkMovementMethod,在他的onTouchEvent中,如果确实是点击的span,则将上边的属性置为true,然后在TextView的onTouchEvent中,返回这个属性即可!(如果点击的是超链接,return true,如果不是超链接,则return false,事件会继续往下分发,检查是否注册的有点击事件,而去响应点击事件!)

你可能感兴趣的:(Android学习笔记,android,textview,link)