美文网首页Android进阶之路Android开发Android开发经验谈
Android 实现TextView的部分文字和网络链接及电话号

Android 实现TextView的部分文字和网络链接及电话号

作者: Android架构木木 | 来源:发表于2019-06-05 17:10 被阅读12次

    前言

    最近在写项目的时候遇到了一个这样的需求,要像qq一样,点击评论的者的名字要跳转评论者的用户信息界面,并且点击评论信息中的web链接要跳转到WebActivity,同时如果是其他数字的话要像qq一样点击并显示底部Dialog提示是播打电话还是复制号码。

    效果

    先给大家看看效果



    下面的评论由一个TextView显示,其实显示为淡蓝的都是可以点击的区域。

    思路

    因为没做过肯定是先百度了解一下,大部分的处理都是先设置TextView的autolink,然后系统会给你判断TextView中是否可以匹配到链接。然后通过SpannableStringBuilder来设置点击事件,当百度的部分有限,只能了解到web链接的点击事件监听,所以我在此基础上并综合直接给TextView设置部分点击的知识做了一些尝试,但是出现了一些问题,就是当autolink设置的过滤在TextView中的文字中没有匹配到的时候不能获取到Spannable对象。我就自己new了一个,但是却不能处罚点击事件,最后找到了一个TextViewtv.setMovementMethod(LinkMovementMethod.getInstance());方法,设置之后才能触发点击事件。

    实现步骤

    首先给你的TextView设置autoLink属性
    如下

    android:autoLink="all"
    

    然后实现一个初始化web和数字链接点击的监听,如下

    public static SpannableStringBuilder getWebLinkStyle(CharSequence text, Context context) {
        if (text instanceof Spannable) {
          int end = text.length();
          Spannable sp = (Spannable) text;
          URLSpan urls[] = sp.getSpans(0, end, URLSpan.class);
          SpannableStringBuilder style = new SpannableStringBuilder(text);
          style.clearSpans();
          for (URLSpan urlSpan : urls) {
            ClickableSpan myURLSpan = new ClickableSpan() {
              @Override
              public void onClick(@NonNull View view) {
                if (urlSpan.getURL().startsWith("http")) {
                  WebActivity.startWebBrowsing(context, urlSpan.getURL(), "");
                } else {
                  String number = urlSpan.getURL();
                  if (number.contains(":")) {
                    number = number.split[1](":");
                  }
                  showBottomSheetDialog(context, number);
                }
              }
            };
            style.setSpan(myURLSpan, sp.getSpanStart(urlSpan),
                sp.getSpanEnd(urlSpan),
                Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
          }
          return style;
        }
        return null;
      }
    
     public static void showBottomSheetDialog(Context context, final String number) {
        BottomSheetDialog dialog = new BottomSheetDialog(context);
        View dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_bottom, null);
        TextView tvTitle = dialogView.findViewById(R.id.tv_title);
        tvTitle.setText(String.format("%s\n可能是一个电话号码或者其他联系方式,你可以", number));
        TextView tvCall = dialogView.findViewById(R.id.tv_call);
        tvCall.setOnClickListener(view -> {
          Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + number));
          context.startActivity(dialIntent);
          dialog.dismiss();
        });
        TextView tvCopty = dialogView.findViewById(R.id.tv_copy);
        tvCopty.setOnClickListener(view -> {
          ClipboardManager copy =
              (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
          copy.setText(number);
          dialog.dismiss();
          ToastHelper.toast("已复制到剪切板");
        });
        TextView tvCancel = dialogView.findViewById(R.id.tv_cancel);
        tvCancel.setOnClickListener(view -> dialog.dismiss());
        dialog.setContentView(dialogView);
        dialog.show();
      }
    

    从这个代码里面可以看到text instanceof Spannable成立的时候即TextView中包含符合autolink过滤的链接。我们可以通过URLSpan来找到对应的链接。然后判断是否为web链接和数字,如果是数字的话显示弹窗,提示打电话或者复制。代码如下,同理如果不成立则说明TextView不包含autolink过滤的链接。只能返回null,需要新建一个。

    接下来就是评论用户设置点击事件了。TextPositionBean是记录每一个评论者用户名在TextView文字中开始和结束的位置,因为在给每个评论者名字加上点击事件时需要给定点击文字的范围。style.setSpan(clickableSpan,textPositionBean.getStart(),textPositionBean.getEnd(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);这其中getStart()和getEnd()就确定了点击文字的范围。
    代码如下

     SpannableStringBuilder style = UiHelper.getWebLinkStyle(tvCommentInfo.getText(),context);
        if (style == null){
          style = new SpannableStringBuilder(stringBuilder.toString());
        }
        for (TextPositionBean<String> textPositionBean : textPositionBeans) {
          ClickableSpan clickableSpan = new ClickableSpan() {
            @Override
            public void onClick(@NonNull View view) {
              UserInfoActivity.goToUserInfoActivity(context,textPositionBean.getData());
            }
          };
          style.setSpan(clickableSpan,textPositionBean.getStart(),textPositionBean.getEnd(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
          tvCommentInfo.setMovementMethod(LinkMovementMethod.getInstance());
        }
        tvCommentInfo.setText(style);
    

    当不存在过滤条件的时候,我就自己手动获取一个,然后根据之前纪录的评论用户的用户名出现的位置,来添加点击事件,并且激活点击响应。即可

    如果需要BottomSheetDialog的布局文件可看如下代码

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
      android:orientation="vertical"
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent">
    
      <TextView
        android:id="@+id/tv_title"
        android:gravity="center"
        android:textColor="#a9a8a8"
        android:textSize="12sp"
        android:layout_width="match_parent"
        android:layout_height="50dp" />
    
      <View
        android:background="#e6e6e6"
        android:layout_width="match_parent"
        android:layout_height="0.3dp"/>
    
      <TextView
        android:id="@+id/tv_call"
        android:text="@string/call"
        android:gravity="center"
        android:textColor="@color/front_black"
        android:textSize="16sp"
        android:layout_width="match_parent"
        android:layout_height="50dp" />
    
      <View
        android:background="#e6e6e6"
        android:layout_width="match_parent"
        android:layout_height="0.3dp"/>
    
      <TextView
        android:id="@+id/tv_copy"
        android:text="@string/copy"
        android:gravity="center"
        android:textColor="@color/front_black"
        android:textSize="16sp"
        android:layout_width="match_parent"
        android:layout_height="50dp" />
    
      <View
        android:background="#dfdfdf"
        android:layout_width="match_parent"
        android:layout_height="10dp"/>
      <TextView
        android:id="@+id/tv_cancel"
        android:text="@string/cancel"
        android:gravity="center"
        android:textColor="@color/front_black"
        android:textSize="16sp"
        android:layout_width="match_parent"
        android:layout_height="50dp" />
    
    </LinearLayout>
    

    写在最后

    很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我整理了一些资料,需要的可以免费分享给大家
    如果喜欢我的文章,想与一群资深开发者一起交流学习的话,获取更多相关大厂面试咨询和指导,欢迎加入我的合作群Android开发交流群:1018342383

    相关文章

      网友评论

        本文标题:Android 实现TextView的部分文字和网络链接及电话号

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