Android自动识别标签的自定义TextView(可自定义点击事件)
16lz
2021-01-26
前言:
项目里遇到这样一个需求,服务器发来一个字符串如下xxxx<a href="http://www.baidu.com">baidu</a>xxxx,xxxx,需要在Android客户端上显示出来,并且点击相应的文字还能打开系统默认浏览器,大体效果如下图:
我的实现思路大体是这样:首先将带有<a>标签的字符串使用正则处理,将<a>标签中的href字段取出,显示文本取出,这个<a>标签在源字符串的起始位置和结束位置取出,用于替换相应文字。通过getUrlFromJDP()方法实现,并返回一个二位数组,这个二位数组的第二维是这段文字的url序号,第一维是url,显示文字,起始结束位置的下标。
将需要的字符串取出之后,通过SpannableString组合多个普通的span和可点击的span实现分段点击效果,并且点击事件可以自定义。
代码实现很简单,只有两个方法:
import android.content.Context;import android.content.Intent;import android.net.Uri;import android.text.SpannableString;import android.text.Spanned;import android.text.method.LinkMovementMethod;import android.text.style.ClickableSpan;import android.util.AttributeSet;import android.util.Log;import android.view.View;import android.widget.TextView;import java.util.ArrayList;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * Created by Administrator on 2016/6/22. */public class AlxUrlTextView extends TextView{ public AlxUrlTextView(Context context, AttributeSet attrs) { super(context, attrs); } public void setText(String text){ if(text==null || text.length()==0)return; Object[][] output = getUrlFromJDP(text); int urlCount = 0; if(output[0]==null || output[0].length==0)return; urlCount = output[0].length; Log.i("AlexUrl","一共有"+urlCount+"个url"); String remainText = text; int lastStart = 0;//截取到一部分后截掉部分的长度 for(int i=0;i<urlCount;i++){ String blueText = (String) output[0][i];//带下划线的文字 final String href = (String) output[1][i];//下划线文字所对应的url连接 int start = (int) output[2][i];//<a>标签在源字符串的起始位置 int end = (int) output[3][i];//<a>标签在源字符串的结束位置 SpannableString spannableString = new SpannableString(blueText); spannableString.setSpan(new ClickableSpan() { //在这里定义点击下划线文字的点击事件,不一定非要打开浏览器 @Override public void onClick(View widget) { //下面是打开系统默认浏览器的方法 Intent intent = new Intent(); intent.setAction("android.intent.action.VIEW"); Uri content_url = Uri.parse(href); intent.setData(content_url); getContext().startActivity(intent); } },0,blueText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); int subStart = start - lastStart; String front = remainText.substring(0,subStart);//截取出一段文字+一段url Log.i("Alex","起始位置"+(end-lastStart)); remainText = remainText.substring(end-lastStart,remainText.length());//剩下的部分 lastStart = end; Log.i("Alex","front是"+front); Log.i("Alex","spann是"+spannableString); Log.i("Alex","remain是"+remainText); if(front.length()>0)append(front); append(spannableString); } if(remainText!=null && remainText.length()>0)append(remainText); setMovementMethod(LinkMovementMethod.getInstance());//响应点击事件 } public static Object[][] getUrlFromJDP(String source){ ArrayList<String> hosts = new ArrayList<>(4); ArrayList<String> urls = new ArrayList<>(4); ArrayList<Integer> starts = new ArrayList<>(4); ArrayList<Integer> ends = new ArrayList<>(4); Pattern pattern = Pattern.compile("<a href=\".*?\">(.*?)</a>");//首先将a标签分离出来 Matcher matcher = pattern.matcher(source); int i=0; while(matcher.find()){ String raw = matcher.group(0); Pattern url_pattern = Pattern.compile("<a href=\"(.*?)\">");//将href分离出来 Matcher url_matcher = url_pattern.matcher(raw); try { if(url_matcher.find()){ String url = url_matcher.group(1); Log.i("Alex","真实url是"+url);//括号里面的 urls.add(i,url); } } catch (Exception e) { e.printStackTrace(); } String host = null;//将要显示的文字分离出来 try { host = matcher.group(1); } catch (Exception e) { e.printStackTrace(); continue; } Log.i("Alex","蓝色文字是"+host);//括号里面的 hosts.add(i,host); starts.add(i,matcher.start()); ends.add(i,matcher.end()); Log.i("Alex","字符串起始下标是"+matcher.start()+"结尾下标是"+matcher.end());//匹配出的字符串在源字符串的位置 i++; } if(hosts.size()==0){ Log.i("Alex","没有发现url"); return null; } Object[][] outputs = new Object[4][hosts.size()];//第一个下标是内容的分类,第二个下标是url的序号 outputs[0] = hosts.toArray(new String[hosts.size()]);//下标0是蓝色的文字 outputs[1] = urls.toArray(new String[urls.size()]);//下标1是url outputs[2] = starts.toArray(new Integer[starts.size()]);//下标2是<a>标签起始位置 outputs[3] = ends.toArray(new Integer[ends.size()]);//下标3是<a>标签结束位置 return outputs; }}
布局文件如下
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" /> <com.example.administrator.googleservicetest.AlxUrlTextView android:id="@+id/tv_url" android:text="" android:textSize="22dp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:layout_width="wrap_content" android:layout_height="wrap_content" /></RelativeLayout>
调用方法如下
AlxUrlTextView textView = (AlxUrlTextView) findViewById(R.id.tv_url); textView.setText("想知道印尼好吃的餐馆都在哪么,看看<a href=\"http://www.qraved.com\">Qraved!</a>你就知道啦,this is a good place to eat dinner with friend,也可以去<a href=\"http://www.baidu.com\">百度</a>获取最新相关资讯");
更多相关文章
- Android(安卓)EditText 限制只能输入指定范围的数字
- Android的文字渲染
- Android自定义View实现竖直跑马灯效果案例解析
- Android之讯飞语音-文字转语音(不用另外安装语音合成包apk)遇到的
- 跟Google学习Android开发-起始篇-构建你的第一个应用程序(3)
- Android字符串及字符串资源的格式化
- Android(安卓)Studio3.0开发JNI流程------JNI中字符串拼接的三种
- 实战:Android活动目录LiveFolder开发
- 完整的Android表情功能处理方案