-
效果图
- 思路:
1 . 用
String.indexOf("")
找到字符串中的下标,我这里添加了4个条件"https://"
、"http://"
、"www."
、"://"
然后分别得到上面4个条件的下标,再从小到大排序下,排序后开始挨个遍历(这里先走的肯定是下标最靠前的了),然后只要满足条件:index != -1(该条件在String中存在)
,就把(index赋值、数据装进list中),break出for循环,再走上面的while循环
后面就遵循上面的规则,最终就可以顺序找出所有满足条件的下标了...2 . 经过第一步,找出了所有
开始下标
,现在再通过各个开始下标
,找出链接的结束下标
:
我从开始下标
开始遍历,拿到当前位置的char,然后判断这个char是不是一些特殊字符或者中文,如果是的话,就设置结束下标
,break;3 . 最后
开始下标
和结束下标
都得到了,设置SpannableStringss
的ClickableSpan
事件.
- 好了,开车了,开车了
//链接识别
public static SpannableString getLinkSpan(Context context, TextView textView, SpannableString ss) {
String ssStr = ss.toString();
//1.算出所有符合条件的开始位置
List<LinkIndexBean> linkStartList = new ArrayList<>();
//当前开始寻找的位置
int index = 0;
while (index != -1 && index < ssStr.length()) {
int httpsStart = ssStr.indexOf("https://", index);
int httpStart = ssStr.indexOf("http://", index);
int wwwStart = ssStr.indexOf("www.", index);
int otherStart = ssStr.indexOf("://", index);
/**
* 核心处
*/
//把四个index排序下
StartLinkBean[] sortArray = geSort(new StartLinkBean[]{new StartLinkBean(httpsStart, 8),
new StartLinkBean(httpStart, 7),
new StartLinkBean(wwwStart, 4),
new StartLinkBean(otherStart, 3)});
//从最小的开始拿,条件满足就跳出for循环,继续走上面的while 都不满足就直接跳出while
for (int i = 0; i < sortArray.length; i++) {
//到最后一个了 先把index赋值为-1 下面如果没有赋值,就跳出while了
if (i == sortArray.length - 1) {
index = -1;
}
if (sortArray[i].getIndex() != -1) {
//把当前下标赋值为当前位置
index = sortArray[i].getIndex() + sortArray[i].getNum();
//数量是4即说明是www. 当前起始位置不是0和前面是:// 就过掉 http://和https://或者://都会走的
if (sortArray[i].getNum() == 4 && sortArray[i].getIndex() >= 3 &&
ssStr.substring(sortArray[i].getIndex() - 3, sortArray[i].getIndex()).equals("://")) {
} else {
//如果这条是:// 起始位置要+3
linkStartList.add(new LinkIndexBean(sortArray[i].getIndex() + (sortArray[i].getNum() == 3 ? 3 : 0)));
}
break;
}
}
}
//2.从所有的起始位置开始查找,再算出结束位置
if (!linkStartList.isEmpty()) {
for (int i = 0; i < linkStartList.size(); i++) {
//从当前开始位置,往后走判断内容
for (int j = linkStartList.get(i).getStart(); j < ssStr.length(); j++) {
char c = ssStr.charAt(j);
// boolean matches = String.valueOf(c).matches("[·`!¥^…()—|、\\[\\]{}【】;:\"‘’“”<>《》,。? ]");
//匹配到了其他不符合规则的字符串 添加结束位置
if (c == '·' || c == '`' || c == '!' || c == '¥' || c == '^' || c == '…' || c == '(' || c == ')' || c == '—' || c == '|' ||
c == '、' || c == '[' || c == ']' || c == '{' || c == '}' || c == '【' || c == '】' || c == ';' || c == ':' || c == '\"' ||
c == '‘' || c == '’' || c == '“' || c == '”' || c == '<' || c == '>' || c == '《' || c == '》' || c == ',' || c == '。' ||
c == '?' || c == ' ' || (c >= 0x4e00 && c <= 0x9fbb)) {
linkStartList.get(i).setEnd(j);
linkStartList.get(i).setStr(ssStr.substring(linkStartList.get(i).getStart(), j));
break;
} else if (j == ssStr.length() - 1) { //或者上面没匹配成功 然后到最后一个了 就添加结束位置
linkStartList.get(i).setEnd(ssStr.length());
linkStartList.get(i).setStr(ssStr.substring(linkStartList.get(i).getStart()));
}
}
}
Random random = new Random();
String[] colors = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
//按照linkStartList里位置设置ss点击事件和颜色改变
for (LinkIndexBean linkIndexBean : linkStartList) {
if (linkIndexBean.getEnd() != -1) {
String color = "#" + colors[random.nextInt(colors.length)]
+ colors[random.nextInt(colors.length)]
+ colors[random.nextInt(colors.length)]
+ colors[random.nextInt(colors.length)]
+ colors[random.nextInt(colors.length)]
+ colors[random.nextInt(colors.length)];
//添加点击事件
ss.setSpan(new ClickableSpan() {
@Override
public void onClick(@NotNull View view) {
Toast.makeText(context, linkIndexBean.getStr(), Toast.LENGTH_SHORT).show();
}
@Override
public void updateDrawState(@NotNull TextPaint textPaint) {
super.updateDrawState(textPaint);
//设置颜色
textPaint.setColor(Color.parseColor(color)); //576B95
//去掉下划线,默认是带下划线的
textPaint.setUnderlineText(false);
// //设置字体背景
// ds.bgColor = Color.parseColor("#FF0000");
}
}, linkIndexBean.getStart(), linkIndexBean.getEnd(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
textView.setMovementMethod(LinkMovementClickMethod.getInstance());
}
return ss;
}
- 从小到大排序
//冒泡排序
private static StartLinkBean[] geSort(StartLinkBean[] array) {
//按里面的index进行冒泡排序
for (int i = array.length - 1; i >= 0; i--) {
boolean flag = true;
for (int j = 0; j < i; j++) {
//进行比较 前面的比后面的大就换位置
if (array[j].getIndex() > array[j + 1].getIndex()) {
StartLinkBean temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
flag = false;
}
}
//优化循环次数
if (flag) {
break;
}
}
return array;
}
- bean
//存放起始位置和要跳过的字符串数量
private static class StartLinkBean {
private int index;
private int num; //当前比较值的数量 比如https:// 就是8
public StartLinkBean(int index, int num) {
this.index = index;
this.num = num;
}
public int getIndex() {
return index;
}
public int getNum() {
return num;
}
}
//链接的起始和结束位置
private static class LinkIndexBean {
private int start;
private String str;
private int end = -1;
public LinkIndexBean(int start) {
this.start = start;
}
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public int getEnd() {
return end;
}
public void setEnd(int end) {
this.end = end;
}
}
- LinkMovementClickMethod
/**
* 处理了父类的onTouch方法,长按后也会同时走ClickableSpan的onClick问题
*/
public class LinkMovementClickMethod extends LinkMovementMethod {
private static LinkMovementClickMethod sInstance;
private final static long CLICK_DELAY = 500;
private long lastClickTime;
public static LinkMovementClickMethod getInstance() {
if (null == sInstance) {
sInstance = new LinkMovementClickMethod();
}
return sInstance;
}
@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);
if (link.length != 0) {
if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
lastClickTime = System.currentTimeMillis();
} else {
//松开时间小于指定时间才触发它的点击事件
if (System.currentTimeMillis() - lastClickTime < CLICK_DELAY) {
link[0].onClick(widget);
}
}
return true;
} else {
Selection.removeSelection(buffer);
}
}
return super.onTouchEvent(widget, buffer, event);
}
}
* 可能性能不是最好的,有更好思路的小伙伴还请多多指教哦