美文网首页
Android在TextView中识别网络链接

Android在TextView中识别网络链接

作者: 一个多洋 | 来源:发表于2020-04-02 11:24 被阅读0次
    • 效果图


      screen.png
      screen.gif

    - 思路:

    • 1 . 用String.indexOf("")找到字符串中的下标,我这里添加了4个条件"https://""http://""www.""://" 然后分别得到上面4个条件的下标,再从小到大排序下,排序后开始挨个遍历(这里先走的肯定是下标最靠前的了),然后只要满足条件:index != -1(该条件在String中存在),就把(index赋值、数据装进list中),break出for循环,再走上面的while循环
      后面就遵循上面的规则,最终就可以顺序找出所有满足条件的下标了...

    • 2 . 经过第一步,找出了所有开始下标,现在再通过各个开始下标,找出链接的结束下标
      我从开始下标开始遍历,拿到当前位置的char,然后判断这个char是不是一些特殊字符或者中文,如果是的话,就设置结束下标,break;

    • 3 . 最后开始下标结束下标都得到了,设置SpannableStringssClickableSpan事件.

    - 好了,开车了,开车了

        //链接识别
        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);
        }
    }
    


    * 可能性能不是最好的,有更好思路的小伙伴还请多多指教哦

    相关文章

      网友评论

          本文标题:Android在TextView中识别网络链接

          本文链接:https://www.haomeiwen.com/subject/ycgtphtx.html