首先感谢此题主及回答的大神提供了思路:点击打开链接
首先问题是这样的:如果LinearLayout中包了一个TextView,TextView设置了ClickableSpan,这时如果恰巧LinearLayout和TextView都设置了点击监听,这时如果点击了ClickableSpan以外的文字,LinearLayout是接收不到监听事件的。
比如:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/ll_sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="30dp">
<TextView
android:id="@+id/tv_sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
package com.muzi.spannablestring;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private LinearLayout mSpLayout;
private TextView mTvSp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSpLayout = (LinearLayout) findViewById(R.id.ll_sp);
mTvSp = (TextView) findViewById(R.id.tv_sp);
mSpLayout.setOnClickListener(this);
mMySpLayout.setOnClickListener(this);
SpannableStringBuilder ssb = new SpannableStringBuilder("nishisdfhisafhisafaof ");
SpannableString spannableString = new SpannableString("btn");
spannableString.setSpan(new ClickableSpan() {
@Override
public void onClick(View widget) {
Toast.makeText(getApplicationContext(), "click btn", Toast.LENGTH_SHORT).show();
}
}, 0, 3, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
ssb.append(spannableString);
mTvSp.setText(ssb);
mTvSp.setMovementMethod(new LinkMovementMethod());
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.ll_sp:
Toast.makeText(getApplicationContext(), "click ll", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
效果如下:
解决方案:
package com.muzi.spannablestring;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.MotionEvent;
import android.widget.TextView;
public class LinkTouchMovementMethod extends LinkMovementMethod {
private ClickableSpan mPressedSpan;
@Override
public boolean onTouchEvent(TextView textView, Spannable spannable, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mPressedSpan = getPressedSpan(textView, spannable, event);
if (mPressedSpan != null) {
Selection.setSelection(spannable, spannable.getSpanStart(mPressedSpan),
spannable.getSpanEnd(mPressedSpan));
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
ClickableSpan touchedSpan = getPressedSpan(textView, spannable, event);
if (mPressedSpan != null && touchedSpan != mPressedSpan) {
mPressedSpan = null;
Selection.removeSelection(spannable);
}
} else {
if (mPressedSpan != null) {
super.onTouchEvent(textView, spannable, event);
}
mPressedSpan = null;
Selection.removeSelection(spannable);
}
return mPressedSpan != null;
}
/**
* Copy from:
* http://stackoverflow.com/questions/20856105/change-the-text-color-of-a-single-clickablespan-when-pressed-without-affecting-o
* By:
* Steven Meliopoulos
*/
private ClickableSpan getPressedSpan(TextView textView, Spannable spannable, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= textView.getTotalPaddingLeft();
y -= textView.getTotalPaddingTop();
x += textView.getScrollX();
y += textView.getScrollY();
Layout layout = textView.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = spannable.getSpans(off, off, ClickableSpan.class);
ClickableSpan touchedSpan = null;
if (link.length > 0) {
touchedSpan = link[0];
}
return touchedSpan;
}
public boolean isPressedSpan() {
return mPressedSpan != null;
}
}
package com.muzi.spannablestring;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.TextView;
/**
* Created by linpu on 18-3-28.
*/
public class MySpannableTextView extends TextView {
private LinkTouchMovementMethod mLinkTouchMovementMethod;
public MySpannableTextView(Context context) {
super(context);
}
public MySpannableTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MySpannableTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = super.onTouchEvent(event);
return mLinkTouchMovementMethod != null ? mLinkTouchMovementMethod.isPressedSpan() : result;
}
public void setLinkTouchMovementMethod(LinkTouchMovementMethod linkTouchMovementMethod) {
mLinkTouchMovementMethod = linkTouchMovementMethod;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/ll_sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="30dp">
<TextView
android:id="@+id/tv_sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="@+id/my_ll_sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="30dp"
android:visibility="gone">
<com.muzi.spannablestring.MySpannableTextView
android:id="@+id/my_tv_sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
package com.muzi.spannablestring;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private LinearLayout mSpLayout;
private TextView mTvSp;
private LinearLayout mMySpLayout;
private MySpannableTextView mMyTvSp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSpLayout = (LinearLayout) findViewById(R.id.ll_sp);
mTvSp = (TextView) findViewById(R.id.tv_sp);
mMySpLayout = (LinearLayout) findViewById(R.id.my_ll_sp);
mMyTvSp = (MySpannableTextView) findViewById(R.id.my_tv_sp);
mSpLayout.setOnClickListener(this);
mMySpLayout.setOnClickListener(this);
SpannableStringBuilder ssb = new SpannableStringBuilder("nishisdfhisafhisafaof ");
SpannableString spannableString = new SpannableString("btn");
spannableString.setSpan(new ClickableSpan() {
@Override
public void onClick(View widget) {
Toast.makeText(getApplicationContext(), "click btn", Toast.LENGTH_SHORT).show();
}
}, 0, 3, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
ssb.append(spannableString);
mTvSp.setText(ssb);
mTvSp.setMovementMethod(new LinkMovementMethod());
SpannableStringBuilder ssb2 = new SpannableStringBuilder("nishisdfhisafhisafaof ");
SpannableString spannableString2 = new SpannableString("mybtn");
spannableString2.setSpan(new ClickableSpan() {
@Override
public void onClick(View view) {
Toast.makeText(getApplicationContext(), "click my btn", Toast.LENGTH_SHORT).show();
}
}, 0, 5, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
ssb2.append(spannableString2);
mMyTvSp.setText(ssb2);
LinkTouchMovementMethod linkTouchMovementMethod = new LinkTouchMovementMethod();
mMyTvSp.setLinkTouchMovementMethod(linkTouchMovementMethod);
mMyTvSp.setMovementMethod(linkTouchMovementMethod);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.ll_sp:
Toast.makeText(getApplicationContext(), "click ll", Toast.LENGTH_SHORT).show();
break;
case R.id.my_ll_sp:
Toast.makeText(getApplicationContext(), "click my ll", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
解决的思路就是:点击时,判断当前点击的区域是否有ClickableSpan,如果有,则拦截TextView的onTouchEvent方法,否则不拦截。
效果如下: