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

下面的評論由一個TextView顯示,其實顯示為淡藍的都是可以點擊的區(qū)域。
思路
因為沒做過肯定是先百度了解一下,大部分的處理都是先設(shè)置TextView的autolink,然后系統(tǒng)會給你判斷TextView中是否可以匹配到鏈接。然后通過SpannableStringBuilder來設(shè)置點擊事件,當(dāng)百度的部分有限,只能了解到web鏈接的點擊事件監(jiān)聽,所以我在此基礎(chǔ)上并綜合直接給TextView設(shè)置部分點擊的知識做了一些嘗試,但是出現(xiàn)了一些問題,就是當(dāng)autolink設(shè)置的過濾在TextView中的文字中沒有匹配到的時候不能獲取到Spannable對象。我就自己new了一個,但是卻不能處罰點擊事件,最后找到了一個TextViewtv.setMovementMethod(LinkMovementMethod.getInstance());方法,設(shè)置之后才能觸發(fā)點擊事件。
實現(xiàn)步驟
首先給你的TextView設(shè)置autoLink屬性
如下
android:autoLink="all"
然后實現(xiàn)一個初始化web和數(shù)字鏈接點擊的監(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可能是一個電話號碼或者其他聯(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();
}
從這個代碼里面可以看到text instanceof Spannable成立的時候即TextView中包含符合autolink過濾的鏈接。我們可以通過URLSpan來找到對應(yīng)的鏈接。然后判斷是否為web鏈接和數(shù)字,如果是數(shù)字的話顯示彈窗,提示打電話或者復(fù)制。代碼如下,同理如果不成立則說明TextView不包含autolink過濾的鏈接。只能返回null,需要新建一個。
接下來就是評論用戶設(shè)置點擊事件了。TextPositionBean是記錄每一個評論者用戶名在TextView文字中開始和結(jié)束的位置,因為在給每個評論者名字加上點擊事件時需要給定點擊文字的范圍。style.setSpan(clickableSpan,textPositionBean.getStart(),textPositionBean.getEnd(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);這其中g(shù)etStart()和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);
當(dāng)不存在過濾條件的時候,我就自己手動獲取一個,然后根據(jù)之前紀(jì)錄的評論用戶的用戶名出現(xià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>