Android 實現TextView的部分文字和網路連結及電話號碼點選監聽
前言
最近在寫專案的時候遇到了一個這樣的需求,要像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,需要新建一個。 接下來就是評論使用者設定點選事件了。 程式碼如下
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>