Android:可点击 TextView 中的 ClickableSpan

Android: ClickableSpan in clickable TextView(Android:可点击 TextView 中的 ClickableSpan)
本文介绍了Android:可点击 TextView 中的 ClickableSpan的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!



I have a textview that can contain clickable links. When one of this links is clicked, I want to start an activity. This works fine, but it should also be possible to click the whole textview and start another activity.


So that's my current solution:

    TextView tv = (TextView)findViewById(;      
    Spannable span = Spannable.Factory.getInstance().newSpannable("test link span");   
    span.setSpan(new ClickableSpan() {  
        public void onClick(View v) {  
            Log.d("main", "link clicked");
            Toast.makeText(Main.this, "link clicked", Toast.LENGTH_SHORT).show(); 
        } }, 5, 9, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

    tv.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            Log.d("main", "textview clicked");
            Toast.makeText(Main.this, "textview clicked", Toast.LENGTH_SHORT).show();               


问题是,当我设置 OnClickListener 时,每次点击链接时首先整个文本视图的监听器然后调用 ClickableSpan 的监听器.

The problem is, that when I set an OnClickListener, everytime I click on a link first the listener for the whole textview and then the one for the ClickableSpan is called.

当点击链接时,有没有办法阻止 android 调用整个 textview 的侦听器?或者在整个视图的监听器中决定是否点击了链接?

Is there a way to prevent android from calling the listener for the whole textview, when a link is clicked? Or to decide in the listener for the whole view, if a link was clicked or not?


Matthew 建议对 TextView 进行子类化,并提出了一个相当丑陋的解决方法.但它有效:

Matthew suggested subclassing TextView and with that hint a came up with a rather ugly workaround. But it works:

我创建了一个ClickPreventableTextView",当我在 TextView 中有可点击的跨度时,我会使用它作为一个整体应该是可点击的.

I've created a "ClickPreventableTextView" which I use when I have clickablespans in a TextView that should be clickable as a whole.

在其 onTouchEvent 方法中,该类在调用其基 TextView 类的 onTouchEvent 之前调用 MovementMethod 的 onTouchEvent 方法.因此,可以保证 clickablespan 的 Listener 将首先被调用.而且我可以防止为整个 TextView 调用 OnClickListener

In its onTouchEvent method this class calls the onTouchEvent method of MovementMethod before calling onTouchEvent on its base TextView class. So it is guaranted, that the Listener of the clickablespan will be invoked first. And I can prevent invoking the OnClickListener for the whole TextView

 * TextView that allows to insert clickablespans while whole textview is still clickable<br>
 * If a click an a clickablespan occurs, click handler of whole textview will <b>not</b> be invoked
 * In your span onclick handler you first have to check whether {@link ignoreSpannableClick} returns true, if so just return from click handler
 * otherwise call {@link preventNextClick} and handle the click event
 * @author Lukas
public class ClickPreventableTextView extends TextView implements OnClickListener {
private boolean preventClick;
private OnClickListener clickListener;
private boolean ignoreSpannableClick;

public ClickPreventableTextView(Context context) {

public ClickPreventableTextView(Context context, AttributeSet attrs) {
    super(context, attrs);

public ClickPreventableTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

public boolean onTouchEvent(MotionEvent event) {
    if (getMovementMethod() != null)
        getMovementMethod().onTouchEvent(this, (Spannable)getText(), event);
    this.ignoreSpannableClick = true;
    boolean ret = super.onTouchEvent(event);
    this.ignoreSpannableClick = false;
    return ret;

 * Returns true if click event for a clickable span should be ignored
 * @return true if click event should be ignored
public boolean ignoreSpannableClick() {
    return ignoreSpannableClick;

 * Call after handling click event for clickable span
public void preventNextClick() {
    preventClick = true;

public void setOnClickListener(OnClickListener listener) {
    this.clickListener = listener;

public void onClick(View v) {
    if (preventClick) {
        preventClick = false;
    } else if (clickListener != null)


The listener for the clickable span now looks like that

    span.setSpan(new ClickableSpan() {  
        public void onClick(View v) {  
            Log.d("main", "link clicked");
            if (widget instanceof ClickPreventableTextView) {
                if (((ClickPreventableTextView)widget).ignoreSpannableClick())

            Toast.makeText(Main.this, "link clicked", Toast.LENGTH_SHORT).show(); 
        } }, 5, 9, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

对我来说主要的缺点是,现在 getMovementMethod().onTouchEvent 将被调用两次(TextView 在它的 onTouchEvent 方法中调用该方法).我不知道这是否有任何副作用,atm 它按预期工作.

For me the main disadvantage is, that now getMovementMethod().onTouchEvent will be called twice (TextView calls that method in it's onTouchEvent method). I don't know if this has any side effects, atm it works as expected.

这篇关于Android:可点击 TextView 中的 ClickableSpan的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!



Android sdk 18 TextView gravity doesn#39;t work vertically(Android sdk 18 TextView 重力不能垂直工作)
Java android: appending a newline using TextView(Java android:使用 TextView 添加换行符)
How to create simple Android TextView and display text on it using java code?(如何使用 java 代码创建简单的 Android TextView 并在其上显示文本?)
Add opaque quot;shadowquot; (outline) to Android TextView(添加不透明的“阴影(大纲)到 Android TextView)
Android: Creating a Circular TextView?(Android:创建一个圆形 TextView?)
Android - set TextView TextStyle programmatically?(Android - 以编程方式设置 TextView TextStyle?)