实现TextView中link的点击效果

朋友们,你们在TextView处理link的时候是不是一直被苦逼的android默认的方式困扰?每次点击link的时候,点击效果是整个textview来响应。非常烂吧?原因就不多赘述了。

那么以下这个控件就适合你了。 gitbub的链接:https://github.com/zhangjizxc/LinkClickTextView

好用的话。帮忙点个赞。

package com.zhang.linkclick;

import com.test.zhang.R;

import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Handler;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.TextView;

/**
 *
 * @author zhangji
 *
 */
public class LinkClickTextView extends TextView {

    private static final String TAG = "LinkClickTextView";
    private ClickableSpan mSelectedLink;
    private boolean mHasPerformedLongPress;
    private CheckForLongPress mPendingCheckForLongPress;
    private ForegroundColorSpan mForegroundColorSpan;
    private UnsetLinkPressedState mUnsetLinkPressedState;

    public LinkClickTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LinkClickTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setLinksClickable(false);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LinkClickTextView, defStyle, 0);
        ColorStateList titleColor = a.getColorStateList(R.styleable.LinkClickTextView_textColorLinkClick);
        if (titleColor != null) {
            mForegroundColorSpan =new ForegroundColorSpan(titleColor.getColorForState(EMPTY_STATE_SET, Color.RED));
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean handled = handledLinkTouch(event);

        if (handled) {
            return true;
        } else {
            return super.onTouchEvent(event);
        }
    }

    @Override
    public void cancelLongPress() {
        removeLongPressCallback();
        super.cancelLongPress();
    }

    @Override
    protected void onDetachedFromWindow() {
        removeLongPressCallback();
        super.onDetachedFromWindow();
    }

    private boolean handledLinkTouch(MotionEvent event) {

        CharSequence text = getText();
        int pointCount = event.getPointerCount();
        if (!(text instanceof Spannable) || pointCount > 1) {
            return false;
        }
        int action = event.getAction();
        Spannable buffer = (Spannable) text;
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                int x = (int) event.getX();
                int y = (int) event.getY();

                x -= this.getTotalPaddingLeft();
                y -= this.getTotalPaddingTop();

                x += this.getScrollX();
                y += this.getScrollY();

                Layout layout = this.getLayout();
                int line = layout.getLineForVertical(y);
                int off = layout.getOffsetForHorizontal(line, x);

                ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
                if (link.length != 0) {
                    checkForLongClick(0);
                    mSelectedLink = link[0];
                    setLinkPressed(true);
                    return true;
                } else {
                    mSelectedLink = null;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (mSelectedLink != null) {
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                if (mSelectedLink != null) {
                    if (!mHasPerformedLongPress) {
                        // This is a tap, so remove the longpress check
                        removeLongPressCallback();
                        mSelectedLink.onClick(this);
                    }
                    if (mUnsetLinkPressedState == null) {
                        mUnsetLinkPressedState = new UnsetLinkPressedState();
                    }
                    postDelayed(mUnsetLinkPressedState,
                            ViewConfiguration.getPressedStateDuration());
                    mSelectedLink = null;
                    return true;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                removeLongPressCallback();
                break;
            default:
                break;
        }
        return false;
    }

    private void checkForLongClick(int delayOffset) {
        if (isLongClickable()) {
            mHasPerformedLongPress = false;

            if (mPendingCheckForLongPress == null) {
                mPendingCheckForLongPress = new CheckForLongPress();
            }
            mPendingCheckForLongPress.rememberWindowAttachCount();
            postDelayed(mPendingCheckForLongPress,
                    ViewConfiguration.getLongPressTimeout() - delayOffset);
        }
    }

    private void removeLongPressCallback() {
        if (mPendingCheckForLongPress != null) {
            removeCallbacks(mPendingCheckForLongPress);
        }
    }

    class CheckForLongPress implements Runnable {

        private int mOriginalWindowAttachCount;

        public void run() {
            if (mOriginalWindowAttachCount == getWindowAttachCount()) {
                if (performLongClick()) {
                    mHasPerformedLongPress = true;
                }
            }
        }

        public void rememberWindowAttachCount() {
            mOriginalWindowAttachCount = getWindowAttachCount();
        }
    }

    private void setLinkPressed(boolean pressed) {
        if (!(getText() instanceof Spannable) || mForegroundColorSpan == null) {
            return;
        }
        Spannable buffer = (Spannable) getText();
        if (buffer == null) {
            return;
        }
        if (pressed) {
            buffer.setSpan(mForegroundColorSpan, buffer.getSpanStart(mSelectedLink),
                    buffer.getSpanEnd(mSelectedLink), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else {
            buffer.removeSpan(mForegroundColorSpan);
        }
    }

    private final class UnsetLinkPressedState implements Runnable {
        public void run() {
            setLinkPressed(false);
        }
    }
}
时间: 2024-10-20 17:46:25

实现TextView中link的点击效果的相关文章

[android篇]textview中片段响应点击事件(SpannableString)

项目需求 点击textView中的一小段文字,弹一个dialog框 失败解决方案 刚开始是用了两个textView水平布局,可想而知,当第一个textView快占满一行,还未换行时,第二个textView很可能出现换行排版问题 用spannableString的问题 小段文字有下划线 点击textView中的小段文字时,系统会当做url处理,给点击部分的text加一个蓝色的背景 解决方案 public class TouchableSpan extends ClickableSpan { pri

Android L中水波纹点击效果的实现

博主参加了2014 CSDN博客之星评选,帮我投一票吧. 点击给我投票 前言 前段时间android L(android 5.0)出来了,界面上做了一些改动,主要是添加了若干动画和一些新的控件,相信大家对view的点击效果-水波纹很有印象吧,点击一个view,然后一个水波纹就会从点击处扩散开来,本文就来分析这种效果的实现.首先,先说下L上的实现,这种波纹效果,L上提供了一种动画,叫做Reveal效果,其底层是通过拿到view的canvas然后不断刷新view来完成的,这种效果需要view的支持,

[androidUI特效]android中TextView中如何设置水平滚动效果

如何让文本实现走马灯的效果,下面就一起实现下吧~~~~~~ package irdc.ScrollingText; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class ScrollingText extends Activity { public TextView t1; /** Called when the activity is first c

css上传图片中等待不可点击效果

<!DOCTYPE html> <html> <head> <title>上传中</title> <style type="text/css"> .dong-hua { position: fixed; left: 0; top: 0; z-index: 10; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.7); color: #ffffff; fo

让低版本的 Android 项目显示出 Material 风格的点击效果

欢迎各位关注我的新浪微博:http://weibo.com/kifile 转载请标明出处(http://blog.csdn.net/kifile) 每天都被不同的需求纠缠的生活是幸福而又不幸的,这不我们家亲爱的设计师们又让我们在低版本的 Android 平台上实现一下类似于 Material Design 的点击效果. 虽然大家都知道 MaterialDesign 的确好看很多,但是让我们为低版本适配也是一个苦逼的活儿. 不过还好,在使用了 nineoldandroids 这个开源库之后,总算是

TextView中超链接拦截

TextView中的超链接点击时,其实是通过Intent方式的,因此会调用Activity中的startActivity(Intent intent)方法,所以可在此方法中做些简单的拦截操作 例如拦截Intent.ACTION_VIEW操作 @Override public void startActivity(Intent intent) { //此处拦截到url使用应用内部webview打开 if(TextUtils.equals(intent.getAction(), Intent.ACT

android selector设置button点击效果(详细)以及常见问题

button的点击效果学习起来事实上比较容易,此点对开发者来说也是使用的比较频繁的一个知识点,与它相关的还有编辑框的获取焦点时改变背景颜色.选择button选择时改变字体颜色等等.这些其实都是用到的drawable的seletor. 当然drawable中还有很多其他效果可以实现,具体的可以参考笔者的另一篇博客: android修改控件外观(使用drawable资源) 效果:(不点击时显示白色,点击时显示灰色) 实现这个效果其实很简单,在drawable中创建一个xml文件,然后输入两行代码即可

AndroidRichText 让Textview轻松的支持富文本(图像ImageSpan、点击效果等等类似QQ微信聊天)

代码地址:https://github.com/Luction/AndroidRichText AndroidRichText帮助实现像QQ,微信一样的,一个TextView里既有文字又有表情又有图片的效果,采用插件化的框架,代码简单,可拓展性强. 基础框架包只有四个java文件, RichTextWrapper :TextView的包裹类,实现支持富文本,通过new RichTextWrapper(TextView v)来构造. RTMovementMethod: 继承自Android原生的L

Android TextView中实现点击文本超链接(无下划线)的封装类

android中有的时候须要在TextView上设置一些超链接,点击这些超链接时进行一些操作.比如新浪微博上的一些keyword,点击时会跳转到对应的页面. 怎样实现我们就直接看源代码吧. /** * * created by Mr.Simple, Aug 21, 20141:51:40 PM. * Copyright (c) 2014, hehonghui@umeng.com All Rights Reserved. * * ##################################