Android 实现TextView的部分文字和网络链接及电话号码点击监听

前言

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

效果

先给大家看看效果

screener_mypublish.png

下面的评论由一个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,需要新建一个。
接下来就是评论用户设置点击事件了。
代码如下

 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>
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值