Android 带html标签文本添加自定义超链接跳转
第一步:在html文本中加入html超链接标签,并做个标识
<a href="privacy">查看用户隐私协议</a>
<a href="important">查看重要声明</a>
这里我们增加了两个超链接,href
的属性值主要用于标记要跳转到哪个APP界面,后面代码处理时会需要根据这个做不同处理
第二步:自定义一个可点击的文本块ClickableSpan
这里主要做了一个简单的封装,关键点在于重写ClickableSpan
的onCLick
方法,它的updateDrawState
方法中则可以修改超链接的一些属性,比如字体颜色,下划线等
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.view.View;
import androidx.annotation.ColorRes;
import androidx.annotation.NonNull;
public class ClickableSpanBuilder {
private View.OnClickListener mListener;//点击事件
private String mUrl;//要打开的网址
private int mLinkColorRes;//超链接颜色
Context mContext;
public ClickableSpanBuilder(Context context) {
this.mContext = context.getApplicationContext();
mLinkColorRes = context.getColor(R.color.common_link_color);//超链接默认字体颜色
}
public ClickableSpanBuilder setClickListener(View.OnClickListener listener) {
this.mListener = listener;
return this;
}
public ClickableSpanBuilder setUrl(String url) {
this.mUrl = url;
return this;
}
public ClickableSpanBuilder setLinkColor(@ColorRes int colorRes) {
this.mLinkColorRes = mContext.getColor(colorRes);;
return this;
}
public ClickableSpan build() {
return new CustomClickableSpan(mContext, mListener, mUrl, mLinkColorRes);
}
private static class CustomClickableSpan extends ClickableSpan {
private View.OnClickListener mListener;//点击事件
private String mUrl;//要打开的网址
private Context mContext;
private int mLinkColorRes;//超链接颜色
public CustomClickableSpan(Context context, View.OnClickListener mListener, String mUrl, int linkColorRes) {
this.mContext = context;
this.mListener = mListener;
this.mUrl = mUrl;
this.mLinkColorRes = linkColorRes;
}
@Override
public void onClick(@NonNull View widget) {
if (mListener != null) {//处理点击事件
mListener.onClick(null);
} else if (!TextUtils.isEmpty(mUrl)) {//如果没有设置,则看是否有设置url
if (mContext != null) {//有的话则使用系统浏览器跳转
mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(mUrl)));
}
}
}
@Override
public void updateDrawState(@NonNull TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(true);//设置需要下划线
ds.setColor(mLinkColorRes);//设置超链接字体颜色
}
}
}
第三步:封装一个工具类,实现处理带html标签的纯文本
工具类中封装了两个方法:
handleContentLink
处理带html标签的文本中所有超链接Spanned sourceContent
这个就是通过Html.fromHtml
解析html后返回的文本内容,其实解析之后html中的<a>
会被解析成URLSpan
对象进行封装- 通过
Spanned
的getSpans
方法可以获取到所有的URLSpan
对象,getSpanStart(URLSpan)
和getSpanEnd(URLSpan)
可以获取指定Span
标签的起始位置和结束位置,也就是<a>xxxxx</a>
包括住的这部分内容前后位置 - 通过
URLSpan
对象的getURL()
方法就可以获取到我们在html中<a>
标签的href
属性值,用于区分该超链接要跳转到哪里 - 还需要创建一个新的
Spanned
对象来保存我们修改后的文本内容,这里我们使用继承于Spanned
的SpannableStringBuilder
,因为它有个clearSpans()
方法可以将之前文本中所有旧的的URLSpan
对象清除;如果不清楚旧的,直接添加新的会导致无法点击跳转 - 通过上一步骤封装的
ClickableSpanBuilder
类创建可以自定义跳转逻辑的ClickableSpan
对象 - 通过
SpannableStringBuilder.setSpan
方法给指定范围的文本设置超链接点击事件
getClickableLink
返回一个可以点击的超链接文本- 用于普通String文本后面需要拼接一个超链接文本Spanned的场景
- String文本和Spanned超链接文本不能直接拼接到一起
- 需要调用
TextView
的append(Spanned)
方法将后面超链接文本拼接进去
import android.content.Context;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.util.Log;
import android.view.View;
public class LinkUtils {
private static final String TAG = "LinkUtils";
/**
* 处理带html标签的文本中所有超链接
* @param context
* @param sourceContent
* @return
*/
public static Spanned handleContentLink(Context context, Spanned sourceContent) {
SpannableStringBuilder tmp = new SpannableStringBuilder(sourceContent);
tmp.clearSpans();//这里必须要清除旧的Span
URLSpan[] urls = sourceContent.getSpans(0, sourceContent.length(), URLSpan.class);//获取所有的超链接标签<a>
for (URLSpan urlSpan : urls) {
Log.i(TAG, "url:" + urlSpan.getURL());
if ("privacy".equals(urlSpan.getURL())) {
ClickableSpan clickableSpan = new ClickableSpanBuilder(context)
.setLinkColor(R.color.common_content_text_color)
.setClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//点击跳转用户隐私协议
}
}).build();
tmp.setSpan(clickableSpan, sourceContent.getSpanStart(urlSpan), sourceContent.getSpanEnd(urlSpan), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if ("important".equals(urlSpan.getURL())) {
ClickableSpan clickableSpan = new ClickableSpanBuilder(context)
.setLinkColor(R.color.common_content_text_color)
.setClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//点击跳转重要声明
}
}).build();
tmp.setSpan(clickableSpan, sourceContent.getSpanStart(urlSpan), sourceContent.getSpanEnd(urlSpan), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
return tmp;
}
/**
* 返回一个可以点击的超链接文本
* @param context
* @param linkText 超链接文本内容
* @param listener 点击事件
* @return
*/
public static Spanned getClickableLink(Context context, String linkText, View.OnClickListener listener) {
SpannableString linkSpan = new SpannableString(linkText);
ClickableSpan clickableSpan = new ClickableSpanBuilder(context)
.setClickListener(listener)
.build();
linkSpan.setSpan(clickableSpan, 0, linkSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return linkSpan;
}
}
第四步:项目中的使用
- 批量处理html文本中超链接用法:
Spanned htmlContent = Html.fromHtml("<a href=\"privacy\">查看用户隐私协议</a><a href=\"important\">查看重要声明</a>");
contentTextView.setText(LinkUtils.handleContentLink(this, htmlContent));
- 纯文本拼接超链接文本用法:
Spanned linkSpan = LinkUtils.getClickableLink(this, "隐私和条款"
, new View.OnClickListener() {
@Override
public void onClick(View v) {
//自定义点击跳转
}
});
String content = "点击查看 ";
textView.setText(content);
textView.append((linkSpan));