Android 實(shí)現(xiàn)TextView的部分文字和網(wǎng)絡(luò)鏈接及電話號(hào)碼點(diǎn)擊監(jiān)聽

前言

最近在寫項(xiàng)目的時(shí)候遇到了一個(gè)這樣的需求,要像qq一樣,點(diǎn)擊評(píng)論的者的名字要跳轉(zhuǎn)評(píng)論者的用戶信息界面,并且點(diǎn)擊評(píng)論信息中的web鏈接要跳轉(zhuǎn)到WebActivity,同時(shí)如果是其他數(shù)字的話要像qq一樣點(diǎn)擊并顯示底部Dialog提示是播打電話還是復(fù)制號(hào)碼。

效果

先給大家看看效果

screener_mypublish.png

下面的評(píng)論由一個(gè)TextView顯示,其實(shí)顯示為淡藍(lán)的都是可以點(diǎn)擊的區(qū)域。

思路

因?yàn)闆]做過肯定是先百度了解一下,大部分的處理都是先設(shè)置TextView的autolink,然后系統(tǒng)會(huì)給你判斷TextView中是否可以匹配到鏈接。然后通過SpannableStringBuilder來設(shè)置點(diǎn)擊事件,當(dāng)百度的部分有限,只能了解到web鏈接的點(diǎn)擊事件監(jiān)聽,所以我在此基礎(chǔ)上并綜合直接給TextView設(shè)置部分點(diǎn)擊的知識(shí)做了一些嘗試,但是出現(xiàn)了一些問題,就是當(dāng)autolink設(shè)置的過濾在TextView中的文字中沒有匹配到的時(shí)候不能獲取到Spannable對(duì)象。我就自己new了一個(gè),但是卻不能處罰點(diǎn)擊事件,最后找到了一個(gè)TextViewtv.setMovementMethod(LinkMovementMethod.getInstance());方法,設(shè)置之后才能觸發(fā)點(diǎn)擊事件。

實(shí)現(xiàn)步驟

首先給你的TextView設(shè)置autoLink屬性
如下

android:autoLink="all"

然后實(shí)現(xiàn)一個(gè)初始化web和數(shù)字鏈接點(diǎn)擊的監(jiān)聽,如下

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可能是一個(gè)電話號(hào)碼或者其他聯(liá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("已復(fù)制到剪切板");
    });
    TextView tvCancel = dialogView.findViewById(R.id.tv_cancel);
    tvCancel.setOnClickListener(view -> dialog.dismiss());
    dialog.setContentView(dialogView);
    dialog.show();
  }

從這個(gè)代碼里面可以看到text instanceof Spannable成立的時(shí)候即TextView中包含符合autolink過濾的鏈接。我們可以通過URLSpan來找到對(duì)應(yīng)的鏈接。然后判斷是否為web鏈接和數(shù)字,如果是數(shù)字的話顯示彈窗,提示打電話或者復(fù)制。代碼如下,同理如果不成立則說明TextView不包含autolink過濾的鏈接。只能返回null,需要新建一個(gè)。
接下來就是評(píng)論用戶設(shè)置點(diǎn)擊事件了。TextPositionBean是記錄每一個(gè)評(píng)論者用戶名在TextView文字中開始和結(jié)束的位置,因?yàn)樵诮o每個(gè)評(píng)論者名字加上點(diǎn)擊事件時(shí)需要給定點(diǎn)擊文字的范圍。style.setSpan(clickableSpan,textPositionBean.getStart(),textPositionBean.getEnd(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);這其中g(shù)etStart()和getEnd()就確定了點(diǎn)擊文字的范圍。
代碼如下

    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);

當(dāng)不存在過濾條件的時(shí)候,我就自己手動(dòng)獲取一個(gè),然后根據(jù)之前紀(jì)錄的評(píng)論用戶的用戶名出現(xiàn)的位置,來添加點(diǎn)擊事件,并且激活點(diǎn)擊響應(yīng)。即可

如果需要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>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容