我有一个包含我们电话号码的文字。我希望无论手机语言是什么都可以点击它们。我研究了自动链接的工作原理,并找到了我尝试在自定义TextView上使用的Linkify.addLinks方法。
public class PhoneNumberLinkTextView extends android.support.v7.widget.AppCompatTextView {
public PhoneNumberLinkTextView(Context context) {
super(context);
}
public PhoneNumberLinkTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public PhoneNumberLinkTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setUSNumberText(CharSequence text) {
SpannableStringBuilder spanText = new SpannableStringBuilder(text);
if (addLinks(spanText)) {
setText(spanText);
} else {
setText(text);
}
}
public boolean addLinks(@NonNull SpannableStringBuilder text) {
ArrayList<LinkSpec> links = new ArrayList<>();
gatherTelLinks(links, text);
if (links.isEmpty()) {
return false;
}
Object[] spans = text.getSpans(0, text.length(), Object.class);
final int count = spans.length;
for (int i = 0; i < count; i++) {
text.removeSpan(spans[i]);
}
for (LinkSpec link: links) {
applyLink(link.url, link.start, link.end, text);
}
return true;
}
private void gatherTelLinks(ArrayList<LinkSpec> links, Spannable s) {
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
Iterable<PhoneNumberMatch> matches = phoneUtil.findNumbers(s.toString(),
Locale.US.getCountry(), PhoneNumberUtil.Leniency.POSSIBLE, Long.MAX_VALUE);
for (PhoneNumberMatch match : matches) {
LinkSpec spec = new LinkSpec();
spec.url = "tel:" + normalizeNumber(match.rawString());
spec.start = match.start();
spec.end = match.end();
links.add(spec);
}
}
private void applyLink(String url, int start, int end, Spannable text) {
URLSpan span = new URLSpan (url);
text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
/**
* Normalize a phone number by removing the characters other than digits. If
* the given number has keypad letters, the letters will be converted to
* digits first.
*
* @param phoneNumber the number to be normalized.
* @return the normalized number.
*/
public String normalizeNumber(String phoneNumber) {
if (TextUtils.isEmpty(phoneNumber)) {
return "";
}
StringBuilder sb = new StringBuilder();
int len = phoneNumber.length();
for (int i = 0; i < len; i++) {
char c = phoneNumber.charAt(i);
// Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
int digit = Character.digit(c, 10);
if (digit != -1) {
sb.append(digit);
} else if (sb.length() == 0 && c == '+') {
sb.append(c);
} else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
return normalizeNumber(PhoneNumberUtils.convertKeypadLettersToDigits(phoneNumber));
}
}
return sb.toString();
}
class LinkSpec {
String url;
int start;
int end;
}
}
此代码目前在视觉上有效。我的美国号码格式符合我的预期,但我的电话号码无法点击。
然后我尝试在setText()之后添加一个setMovementMethod(LinkMovementMethod.getInstance()),但这次我丢失了格式化为电话号码的美国号码。
有谁知道我如何才能实现我想要做的事情?
答案 0 :(得分:0)
我通过扩展ClickableSpan的自定义类替换了URLSpan来解决我的问题。
private class USNumberSpan extends ClickableSpan {
private String url;
USNumberSpan(String url) {
this.url = url;
}
@Override
public void onClick(View widget) {
Uri uri = Uri.parse(url);
Context context = widget.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w("URLSpan", "Activity was not found for intent, " + intent.toString(), e);
}
}
}
我没有找到为什么这样做有效,而URLSpan不是,但我很高兴它有效。
答案 1 :(得分:0)
在此链接上,我找到了Kotlin答案(由用户Iliya Mashin提出),其中包含针对任何类型的数字的模式:android:autoLink for phone numbers doesn't always work
我为Java对其进行了修改,并至少指定了4个数字(因此它不会链接一些以3个数字“ xxxxx-xxx”结尾的邮政编码),因此,如果您不希望使用此特定限制,则只需删除表达式末尾的“ {4,}”。
LinkifyCompat.addLinks(textView, Linkify.ALL); // This will use the usual linkify for any other format
Pattern pattern = Pattern.compile("([\\d|\\(][\\h|\\(\\d{3}\\)|\\.|\\-|\\d]{4,}\\d{4,})", Pattern.CASE_INSENSITIVE);
LinkifyCompat.addLinks(textView, pattern, "tel://", null, null, null); // this adds the format for all kinds of phone number
如果只想链接数字,请删除第一行(带有“ Linkify.ALL”的那一行)。