Andorid TextView,Linkify美国各种语言的电话号码

时间:2018-01-03 13:05:06

标签: android textview linkify

我有一个包含我们电话号码的文字。我希望无论手机语言是什么都可以点击它们。我研究了自动链接的工作原理,并找到了我尝试在自定义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()),但这次我丢失了格式化为电话号码的美国号码。

有谁知道我如何才能实现我想要做的事情?

2 个答案:

答案 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”的那一行)。