赞
踩
背景:
在项目开发过程中,需要在用户协议等文本中加入超链接跳转到APP内的其他界面,正常情况下我们都会知道用Html.fromHtml
来识别html标签中的超链接,比如<a href="http://www.baidu.com/">百度一下</a>
,点击时会自动打开系统浏览器去跳转,但是如果我们不想跳转浏览器打开网页,而是需要跳转到APP内的某个界面,则需要额外处理
<a href="privacy">查看用户隐私协议</a>
<a href="important">查看重要声明</a>
这里我们增加了两个超链接,href
的属性值主要用于标记要跳转到哪个APP界面,后面代码处理时会需要根据这个做不同处理
这里主要做了一个简单的封装,关键点在于重写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);//设置超链接字体颜色 } } }
工具类中封装了两个方法:
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
返回一个可以点击的超链接文本
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; } }
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));
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。