TextView的内部链接与onClick事件冲突

在一个TextView内显示富态文本,例如指定文本的颜色、链接、大小等等

详见: TextView使用SpannableString设置复合文本

常用的如: Android使用TextView实现无下划线超链接

一般加入链接地址是直接Html.fromHTML(str)或者使用URLSpan,如下:

String str = "浪人风子";
SpannableString spanText = new SpannableString(str + " ——CSDN");
spanText.setSpan(new URLSpan("http://blog.csdn.net/langrenfengzi"), 0, str.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setText(spanText);
textView.setMovementMethod(new LinkMovementMethod());
这样显示的应该是这样带有下划线:  浪人风子 ——CSDN

对链接自动添加下划线及颜色略有不同。


继承URLSpan类,覆写updateDrawState方法:

/**
 * 
 * 没有下划线的URLSpan
 *
 */
public class URLSpanWithoutUnderLine extends URLSpan {

	private int color = 0xff000000;

	public URLSpanWithoutUnderLine(String url, int color) {
		super(url);
		this.color = color;
	}
	
	public URLSpanWithoutUnderLine(String url) {
		super(url);
	}

	public URLSpanWithoutUnderLine(Parcel src) {
		super(src);
	}

	public void setColor(int color){
		this.color  = color;
	}
	
	@Override
	public void updateDrawState(TextPaint ds) {
		
		ds.setUnderlineText(false);//去掉下划线
		ds.setColor(color);//改成指定颜色
	}
}

String str = "浪人风子";
SpannableString spanText = new SpannableString(str + " ——CSDN");
spanText.setSpan(new URLSpanWithoutUnderLine("http://blog.csdn.net/langrenfengzi", Color.BLUE), 0, str.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setText(spanText);
textView.setMovementMethod(new LinkMovementMethod());
这样就实现了蓝色文字无下划线带链接的文字:  浪人风子 ——CSDN

如果给TextView设置带点击事件OnClickListener,发现当点击链接的时候,点击事件也会被调用。

textView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("test", "onClick.");
    }
});


我们想要实现的是当点击链接文字的时候只跳转链接不触发点击事件,当点击其他位置的时候只触发点击事件。

继承LinkMovementMethod类,重写onTouchEvent方法,使用一个flag标志何时点击了链接。

另外需要对TextView进行自定义控件,当flag标志的时候屏蔽点击事件。

public class CommentTextView extends TextView {

    public boolean linkHit;//内部链接是否被点击
    
    public CommentTextView(Context context) {
        super(context);
    }
    public CommentTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public CommentTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    
    @Override
    public boolean performClick() {
        if(linkHit){
            return true;
        }
        return super.performClick();
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        linkHit = false;
        return super.onTouchEvent(event);
    }
    
}


参考:http://www.cnblogs.com/TerryBlog/archive/2013/04/02/2994815.html

http://stackoverflow.com/questions/8558732/listview-textview-with-linkmovementmethod-makes-list-item-unclickable


public class CustomLinkMovementMethod extends LinkMovementMethod {

static CustomLinkMovementMethod 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 CommentTextView){
                    ((CommentTextView)widget).linkHit = true;
                }
                
                return true;
            } else {
                Selection.removeSelection(buffer);
                super.onTouchEvent(widget, buffer, event);
                return false;
            }
        }

        return Touch.onTouchEvent(widget, buffer, event);
    }
    
    public static CustomLinkMovementMethod getInstance() {
        if(sInstance == null){
            sInstance = new CustomLinkMovementMethod();
        }
        return sInstance;
    }
}

CustomLinkMovementMethod的onTouchEvent基本拷贝LinkMovementMethod里对应方法的内容,需要修改的部分用为当有点击链接的时候设置flag变量linkHit.

另外切记,务必要重写静态方法getInstance(), 否则会调用父类的getInstance()实现,继而调用父类的onTouchEvent方法,实则没起作用。

在CommentTextView的onTouchEvent方法中的super.onTouchEvent(event)方法中会自动调用CustomLinkMovementMethod的onTouchEvent()方法,然后修改linkHit的值。

在performClick中判断,当linkHit为true的时候,直接返回true, 屏蔽调后续的onClickListener里的实现。

最终这样来调用:

CommentTextView textView = new CommentTextView(this);
String str = "浪人风子";
SpannableString spanText = new SpannableString(str + " ——CSDN");
spanText.setSpan(new URLSpanWithoutUnderLine("http://blog.csdn.net/langrenfengzi", Color.BLUE), 0, str.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setText(spanText);
textView.setMovementMethod(CustomLinkMovementMethod.getInstance());








  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值