在TextView中包含局部可点击的链接,且改链接其他地方也是有相应的点击事件,文本中定义了格式, public void setSpan(Object what, int start, int end, int flags) {}点击得知道在文本中哪些文字是需要点击的。
Examples 格式:Hello Android <b>Click Detail # https://www.baidu.com</b>
需求:
(1) <b> --- # 显示:字体蓝色可以点击.
(2) # --- </b> 不显示:蓝色字体点击后的URL.
(3) 默认字体为黑色。
1.按照流程先获取<b> 到</b>中的文字,截取出来拼接到原来文字,URL通过setSpan(new ClickableSpan())来设置点击事件进行跳转.
有大神说了,substring()截取通过ClickableSpan点击多简单哇,这还用你说,看看下面:
如果Examples 格式不固定:<b>ClickableSpan可以让我们在点击TextView相应文字时响应点击事件# https://www.baidu.com</b>,比如常用的URLSpan,会在点击时打开相应的链接。而为了让TextView能够响应ClickableSpan的点击,<b>我们需要为它设置LinkMovementMethod,# https://www.baidu.com</b>但是这个\n\n" <b>LinkMovementMethod又有着很大的坑# https://www.csdn.net</b> <b>LinkMovementMethod又有着很大的坑# https://www.baidu.com</b>你咋解决,有很多,setMovementMethod(LinkMovementMethod.getInstance())滑动、空格、换行.
效果图:
//设置TextView中的超链接可点击spannableTextView.setMovementMethod(LinkMovementMethod.getInstance());
*支持Textview设置富文本点击
*设置Textview 中部分字设置可以点击、变色,
*设置setMovementMethod(LinkMovementMethod.getInstance())后click与Textview滑动冲突.
*解决点击空白区域依然有点击事件
//1. 截取并设置点击 Help class
public class MyDataHelp {
public static final String TAG = MyDataHelp.class.getSimpleName();
private static String start_label = "<b>", sub_label = "#", end_label = "</b>", http = "http";//设置截取的格式
//处理数据
public static void dealWithContent(String with_content, final CallBack callBack) {
Log.i(TAG, "获取到的content: " + with_content);
try {
final ArrayList<String> list = new ArrayList<>();
//按照</b>截取,看看有几个可以点击需要进行数据处理
String[] split = with_content.split(end_label);
for (String split_content : split) {
if (split_content.contains(start_label) && split_content.contains(sub_label)) {
String substring = split_content.substring(split_content.indexOf(start_label), split_content.length());
Log.i(TAG, "substring : " + substring);
list.add(substring);
}
}
ArrayList<String> list_title = new ArrayList<>(); //截取<b> --- # 显示的文字 list
final ArrayList<String> list_url = new ArrayList<>(); //截取<b> --- # URL
for (int i = 0; i < list.size(); i++) {
if (with_content.contains(list.get(i))) {
String list_content = list.get(i);
String sub_title = list_content.substring(list_content.indexOf(start_label) + 3, list_content.indexOf(sub_label));
final String url;
if (list_content.contains(http)) {
url = list_content.substring(list_content.indexOf(http), list_content.length());
} else {
url = list_content.substring(list_content.indexOf(sub_label) + 2, list_content.length());
}
String start = with_content.substring(0, with_content.indexOf(start_label));
String end = with_content.substring(with_content.indexOf(end_label) + 4, with_content.length());
String all_text = start + sub_title + end;
with_content = all_text;
Log.i(TAG, "all_text : " + all_text);
list_title.add(sub_title);
list_url.add(url);
Log.i(TAG, "sub_title : " + sub_title + " url: " + url);
}
}
SpannableStringBuilder ssb = new SpannableStringBuilder(with_content);//进行拼接和设置点击事件
int indexOf = 0;
for (int i = 0; i < list_title.size(); i++) {
String list_text = list_title.get(i);
list_text.replaceAll(" ", "");//替换中间的空格
final String URL = list_url.get(i);
Log.i(TAG, "list_text : " + list_text + " URL: " + URL);
//为了解决重复<b>Click Detail # https://www.baidu.com</b> 好多相同的indexOf默认只取第一个,接着往下遍历.
indexOf = with_content.indexOf(list_text, i == 0 ? 0 : indexOf + list_text.length());
if (indexOf == -1) {//找不到会返回-1,只好再重新查找
indexOf = with_content.indexOf(list_text);
}
//设置点击文字的click和颜色
ssb.setSpan(new ForegroundColorSpan(Color.parseColor("#2497df")), indexOf, indexOf + list_text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
ssb.setSpan(new ClickableSpan() {
@Override
public void onClick(@NonNull View view) {
Log.i(TAG, "click url: " + URL);
callBack.dealUrl(URL);
}
@Override
public void updateDrawState(@NonNull TextPaint ds) {
ds.setUnderlineText(false); //去除超链接的下划线
}
}, indexOf, indexOf + list_text.length() - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //list_text.length() - 1为了解决点击空白区域依然有点击事件
Log.i(TAG, "ssb : " + ssb);
}
callBack.dealText(ssb);
} catch (Exception e) {
Log.i(TAG, "e.getMessage(): " + e.getMessage());//必要时走try
}
}
public interface CallBack {
void dealText(SpannableStringBuilder text);
void dealUrl(String URL);
}
}
// 2. 解决布局clcik与TextView本身滑动冲突
public class MyTextView extends TextView {
private static String TAG = "MyTextView";
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public boolean linkHit;//内部富文本是否被点击
private static long lastClickTime;
private static final long CLICK_DELAY = 500l;
@Override
public boolean performClick() { //最后响应3
if (linkHit) {
return true; //这样textView的OnClick事件不会响应
}
return super.performClick(); //调用监听的onClick方法
}
@Override
public boolean onTouchEvent(MotionEvent event) { //textView的OnClick事件响应,首先响应1
linkHit = false;
return super.onTouchEvent(event);
}
public static class CustomLinkMovementMethod extends LinkMovementMethod { //次之2
static CustomLinkMovementMethod sInstance;
//手指按下的点为(x1, y1)手指离开屏幕的点为(x2, y2)
float x1 = 0;
float x2 = 0;
float y1 = 0;
float y2 = 0;
@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);
//解决拦截滑动时触发Textview link 点击事件
if (action == MotionEvent.ACTION_UP) {
//当手指离开的时候
x2 = event.getX();
y2 = event.getY();
if (y1 - y2 > 50) {
Log.i(TAG, "向上滑");
link = new ClickableSpan[0];
} else if (y2 - y1 > 50) {
Log.i(TAG, "向下滑");
link = new ClickableSpan[0];
}
} else {
//当手指按下的时候
x1 = event.getX();
y1 = event.getY();
}
//不是滑动、link.length != 0,拦截处理 Textview link 点击事件 ,证明点击了
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
link[0].onClick(widget);
return true;
}
} else {
Selection.removeSelection(buffer);
}
}
return Touch.onTouchEvent(widget, buffer, event);
}
public static CustomLinkMovementMethod getInstance() {
if (sInstance == null) {
sInstance = new CustomLinkMovementMethod();
}
return sInstance;
}
}
}
// 3. Textview 赋值
MyDataHelp.dealWithContent(content, new MyDataHelp.CallBack() {//处理富文本格式数据
@Override
public void dealText(SpannableStringBuilder ssb) {
tv_content.setText(ssb);
tv_content.setMovementMethod(MyTextView.CustomLinkMovementMethod.getInstance());//解决点击事件与Textview本身滑动冲突
tv_content.setHighlightColor(ContextCompat.getColor(getContext(), R.color.white));//去掉点击后的背景颜色为透明
}
@Override
public void dealUrl(String URL) {
clickListenerInterface.doLink(URL);
}
});
如有其他解决方法可以告诉我
下载Demo地址