Android 带html标签文本添加自定义超链接跳转

Android 带html标签文本添加自定义超链接跳转

背景:
在项目开发过程中,需要在用户协议等文本中加入超链接跳转到APP内的其他界面,正常情况下我们都会知道用Html.fromHtml来识别html标签中的超链接,比如<a href="http://www.baidu.com/">百度一下</a>,点击时会自动打开系统浏览器去跳转,但是如果我们不想跳转浏览器打开网页,而是需要跳转到APP内的某个界面,则需要额外处理

第一步:在html文本中加入html超链接标签,并做个标识

<a href="privacy">查看用户隐私协议</a>
<a href="important">查看重要声明</a>

这里我们增加了两个超链接,href的属性值主要用于标记要跳转到哪个APP界面,后面代码处理时会需要根据这个做不同处理

第二步:自定义一个可点击的文本块ClickableSpan

这里主要做了一个简单的封装,关键点在于重写ClickableSpanonCLick方法,它的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;}@Overridepublic void onClick(@NonNull View widget) {if (mListener != null) {//处理点击事件mListener.onClick(null);} else if (!TextUtils.isEmpty(mUrl)) {//如果没有设置,则看是否有设置urlif (mContext != null) {//有的话则使用系统浏览器跳转mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(mUrl)));}}}@Overridepublic 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对象进行封装
    • 通过SpannedgetSpans方法可以获取到所有的URLSpan对象,getSpanStart(URLSpan)getSpanEnd(URLSpan)可以获取指定Span标签的起始位置和结束位置,也就是<a>xxxxx</a>包括住的这部分内容前后位置
    • 通过URLSpan对象的getURL()方法就可以获取到我们在html中<a>标签的href属性值,用于区分该超链接要跳转到哪里
    • 还需要创建一个新的Spanned对象来保存我们修改后的文本内容,这里我们使用继承于SpannedSpannableStringBuilder,因为它有个clearSpans()方法可以将之前文本中所有旧的的URLSpan对象清除;如果不清楚旧的,直接添加新的会导致无法点击跳转
    • 通过上一步骤封装的ClickableSpanBuilder类创建可以自定义跳转逻辑的ClickableSpan对象
    • 通过SpannableStringBuilder.setSpan方法给指定范围的文本设置超链接点击事件
  • getClickableLink 返回一个可以点击的超链接文本
    • 用于普通String文本后面需要拼接一个超链接文本Spanned的场景
    • String文本和Spanned超链接文本不能直接拼接到一起
    • 需要调用TextViewappend(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();//这里必须要清除旧的SpanURLSpan[] 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() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onClick(View v) {//自定义点击跳转}});
String content = "点击查看 ";
textView.setText(content);
textView.append((linkSpan));

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/767219.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SpringMVC】知识汇总

SpringMVC 短暂回来&#xff0c;有时间就会更新博客 文章目录 SpringMVC前言一、第一章 SpingMVC概述二、SpringMVC常用注解1. Controller注解2. RequestMapping注解3. ResponseBody注解4. RequestParam5. EnableWebMvc注解介绍6. RequestBody注解介绍7. RequestBody与RequestP…

Echarts功能记录

基础配置 工具箱toolbox 对应功能 案例中使用到的第三方脚本

SpringBoot 启用 Https,生成 jks 自签证书

使用 Java 提供的工具生成 jks 自签证书 keytool 是 Java Development Kit (JDK) 中的一个工具&#xff0c;用于管理公钥和私钥对以及相关的证书。以下命令用于生成一个密钥对并将其存储在密钥库中&#xff1a; keytool -genkeypair -alias www.example.com -keyalg RSA -key…

解决Animate.css动画效果无法在浏览器运行问题

背景 在开发官方网站的时候&#xff0c;临时更换了电脑&#xff0c;发现原本正常的动画效果突然不动了。 经过 chrome、Microsoft Edge都无法运行。 Animate.css | A cross-browser library of CSS animations. 问题排查 通过审查元素后发现类名是注入并且生效的。 验证 然…

开源科学可视化软件

目录 0 参考链接 1 GR 2 VisIt 3 Inviwo 4 Voreen 5 MegaMol 6 ParaView 7 ROOT 8 Mayavi 9 PyQtGraph 10 vedo 11 Glumpy 12 SCIRun 13 Vispy 14 K3D 15 VTK 16 yt 17 Veusz 18 PyVista 18 TTK 20 Ipyvolume 21 Polyscope 22 GLVis 23 3D Slicer …

【图解物联网】第3章 物联网设备

3.1 设备——通向显示世界的接口 3.1.1 为什么要学习设备的相关知识 经过前两章的学习&#xff0c;想必各位读者已经掌握物联网这个词描绘出的世界和用于实现物联网的系统架构了。基于这点&#xff0c;这一章将会为大家介绍在物联网世界中起着核心作用的因素&#xff0c;即设…

atoi函数(想要彻底了解atoi函数,那么看这一篇就足够了!)

前言&#xff1a;在学习C语言的时候&#xff0c;我们知道每个字符都有其所对应的ASCII码值&#xff0c;当我们使用49来打印字符时&#xff0c;打印出来的就是数字字符 ‘ 1 ’&#xff0c;那么字符能否直接被转换成对应的整型数字呢&#xff1f;答案是当然可以&#xff0c;这时…

印度洋涡旋统计

印度洋涡旋统计 clear;clc;clf;close all; %% 读取涡旋半径、时间范围、经纬度信息,以及涡旋点的经纬度;半径路径和涡旋极性; file2=‘D:\matlab_work\accept_work\涡旋统计的平面分布\eddy_trajectory_2.0exp_19930101_20200307.nc’; time=double(ncread(file2,‘time’)…

一文搞懂数据链路层

数据链路层 1. 简介2. MAC3. 以太网 1. 简介 &#xff08;1&#xff09;概念 链路(link)是一条无源的点到点的物理线路段&#xff0c;中间没有任何其他的交换结点。 数据链路(data link) 除了物理线路&#xff08;双绞线电缆、同轴电缆、光线等介质&#xff09;外&#xff0…

2024-03-24 成长-周复盘-责任与能力-事情的推进与落地和完成

摘要: 过于一周发生太多事情&#xff0c;林林总总&#xff0c;有些事情为了避免重蹈覆辙&#xff0c;要进行回溯复盘。 主要集中于做事方式&#xff0c;做事方法&#xff0c;更多的是集中于失败的做事方式。 在认知层面&#xff0c;要通过做事的结果&#xff0c;来反向推导做…

详细安装步骤:vue.js 三种方式安装(vue-cli)

Vue.js&#xff08;读音 /vjuː/, 类似于 view&#xff09;是一个构建数据驱动的 web 界面的渐进式框架。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。它不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。 三种 Vue.js 的安装方法&…

二进制王国【蓝桥杯算法双周赛】

原题链接:https://www.lanqiao.cn/problems/17035/learning/?contest_id177 #include <bits/stdc.h> using namespace std;bool cmp(const string &x,const string &y) {return xy<yx; }int main() {int n; cin>>n;vector<string> vt(n);for(in…

Dockerfile优化

使用多阶段构建 go应用程序 # Build stage FROM golang:1.16 AS build WORKDIR /app COPY . . RUN go build -o myapp .# Runtime stage FROM alpine:latest WORKDIR /root/ COPY --frombuild /app/myapp . CMD ["./myapp"]Nodejs应用程序 # Build stage FROM nod…

matlab 将矩阵写入文件

目录 一、概述1、算法概述2、主要函数二、将矩阵写入到文本文件三、将矩阵写入电子表格文件四、将矩阵写入指定的工作表和范围五、将数据追加到电子表格六、将矩阵数据追加到文本文件七、参考链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此…

Debezium日常分享系列之:Debezium2.5稳定版本之处理常见问题

Debezium日常分享系列之&#xff1a;Debezium2.5稳定版本之处理常见问题 一、配置和启动错误二、MySQL 不可用三、Kafka Connect stops gracefully四、Kafka Connect 进程崩溃五、Kafka变得不可用六、MySQL 清除 binlog 文件七、Debezium技术总结 下面描述 Debezium 如何处理各…

代码随想录阅读笔记-栈与队列【删除字符串中的所有相邻重复项】

题目 给出由小写字母组成的字符串 S&#xff0c;重复项删除操作会选择两个相邻且相同的字母&#xff0c;并删除它们。 在 S 上反复执行重复项删除操作&#xff0c;直到无法继续删除。 在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。 示例&#xff1a; 输入&am…

了解交互设计:定义、解析及案例演示!

交互设计作为现代设计领域的一个重要分支&#xff0c;对用户体验和产品的成功至关重要。然而&#xff0c;许多人并不了解交互设计的定义和实践方法。本文将深入分析交互设计的概念和重要性&#xff0c;分享精彩的案例&#xff0c;推荐有用的交互设计工具&#xff0c;帮助您创造…

解析SpringBoot自动装配原理前置知识:解析条件注释的原理

什么是自动装配&#xff1f; Spring提供了向Bean中自动注入依赖的这个功能&#xff0c;这个过程就是自动装配。 SpringBoot的自动装配原理基于大量的条件注解ConditionalOnXXX&#xff0c;因此要先来了解一下条件注解相关的源码。 以ConditionalOnClass为例 首先来查看Conditi…

02-MySQL数据库的基本使用与密码设置

一、服务端口 3306端口和33060端口&#xff0c;是我们启动数据库后开启的监听端口&#xff1b; 3306端口&#xff1a;是我们MySQL服务的监听端口&#xff0c;用来连接数据库使用&#xff1b; 33060端口&#xff1a;MySQL-shell服务的端口&#xff0c;MySQL-shell是MySQL架构集群…

Web前端-JS

JavaScript&#xff0c;简称js&#xff1a;负责网页的行为&#xff08;交互效果&#xff09;。是一门跨平台&#xff0c;面向对象的脚本语言&#xff08;编写出来的语言不需要编译&#xff0c;通过浏览器的解释就可以运行&#xff09; JS引入方式 1.内嵌样式 这样打开页面就会…