Пользовательские вкладки Chrome и просмотр текста

У меня есть текстовое представление со ссылкой внутри. В коде я называю setMovementMethod открыть ссылку, когда пользователь нажимает на текст. Но он открывает его в браузере по умолчанию или в браузере.

Как использовать пользовательские вкладки Chrome с интерактивным просмотром текста?

3 ответа

Решение

Это потому что TextView создает URLSpan который ClickableSpan для каждого шаблона текста ссылки. Однажды MovementMethod находит URL это звонки onClick метод URLSpan, Это событие начинает ACTION_VIEW намерение, поэтому вы видите, что браузер по умолчанию запускается вместо этого.

Что вы можете сделать, это написать свою собственную реализацию URLSpanгде вы переопределите метод onClick и запустите CustomTabs сервис оттуда.

Сначала создайте кастом URLSpan это переопределит onClick метод:

public class CustomTabsURLSpan extends URLSpan {
    public CustomTabsURLSpan(String url) {
        super(url);
    }

    public CustomTabsURLSpan(Parcel src) {
        super(src);
    }

    @Override
    public void onClick(View widget) {
       String url = getUrl();
       //attempt to open in CustomTabs, if that fails call super.onClick(widget);
    }
}

Создайте собственный метод преобразования, который установит интервалы для ссылок:

public class LinkTransformationMethod implements TransformationMethod {

    @Override
    public CharSequence getTransformation(CharSequence source, View view) {
        if (view instanceof TextView) {
            TextView textView = (TextView) view;
            Linkify.addLinks(textView, Linkify.WEB_URLS);
            String stringText = textView.getText().toString();
            Spannable text = (Spannable) textView.getText();
            URLSpan[] spans = text.getSpans(0, textView.length(), URLSpan.class);
            for (int i = spans.length - 1; i >= 0; i--) {
                URLSpan oldSpan = spans[i];
                text.removeSpan(oldSpan);
                String url = oldSpan.getURL();
                int startIndex = stringText.indexOf(url);
                int lastIndex = startIndex + url.length();
                text.setSpan(new CustomTabsURLSpan(url), startIndex, lastIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
            return text;
        }
        return source;
    }

    @Override
    public void onFocusChanged(View view, CharSequence sourceText, boolean focused, int direction, Rect previouslyFocusedRect) {

    }
}

И вот краткое объяснение: https://medium.com/@nullthemall/make-textview-open-links-in-customtabs-12fdcf4bb684

Я немного изменил ответ Никола, чтобы он все еще работал и для других опций линковки.

я добавил Patterns.WEB_URL.matcher() и конструктор, чтобы установить, какие параметры ссылок вы хотите.

Использование:

textView.setTransformationMethod(new LinkTransformationMethod(Linkify.WEB_URLS | 
    Linkify.EMAIL_ADDRESSES | 
    Linkify.PHONE_NUMBERS));

Сам полный класс:

public class LinkTransformationMethod implements TransformationMethod {

    private final int linkifyOptions;

    public LinkTransformationMethod(int linkifyOptions) {
        this.linkifyOptions = linkifyOptions;
    }

    @Override
    public CharSequence getTransformation(CharSequence source, View view) {
        if (view instanceof TextView) {
            TextView textView = (TextView) view;
            Linkify.addLinks(textView, linkifyOptions);
            if (textView.getText() == null || !(textView.getText() instanceof Spannable)) {
                return source;
            }
            Spannable text = (Spannable) textView.getText();
            URLSpan[] spans = text.getSpans(0, textView.length(), URLSpan.class);
            for (int i = spans.length - 1; i >= 0; i--) {
                URLSpan oldSpan = spans[i];
                int start = text.getSpanStart(oldSpan);
                int end = text.getSpanEnd(oldSpan);
                String url = oldSpan.getURL();
                if (!Patterns.WEB_URL.matcher(url).matches()) {
                    continue;
                }
                text.removeSpan(oldSpan);
                text.setSpan(new ChromeTabsUrlSpan(url), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
            return text;
        }
        return source;
    }

    @Override
    public void onFocusChanged(View view, CharSequence sourceText, boolean focused, int direction, Rect previouslyFocusedRect) {

    }
}

Вот вариант Котлина, основанный на ответе Николы. Я также позволил себе добавить обработку URL-адресов в пользовательской вкладке Chrome:

      import android.graphics.Rect
import android.net.Uri
import android.os.Parcel
import android.text.Spannable
import android.text.Spanned
import android.text.method.TransformationMethod
import android.text.style.URLSpan
import android.text.util.Linkify
import android.util.Log
import android.view.View
import android.widget.TextView
import androidx.browser.customtabs.CustomTabsIntent

class LinkTransformationMethod : TransformationMethod {

    private val TAG = LinkTransformationMethod::class.java.simpleName

    inner class CustomTabsURLSpan : URLSpan {
        constructor(url: String?) : super(url)
        constructor(src: Parcel?) : super(src!!)

        override fun onClick(widget: View) {
            try {
                CustomTabsIntent.Builder()
                    .build()
                    .launchUrl(widget.context, Uri.parse(url))
            } catch (exception: Exception) {
                Log.e(TAG, "Failed to open link in custom tab!", exception)
                super.onClick(widget)
            }
        }
    }

    override fun getTransformation(source: CharSequence?, view: View?): CharSequence? {
        if (view is TextView) {
            Linkify.addLinks(view, Linkify.WEB_URLS)
            if (view.text == null || view.text !is Spannable) {
                return source
            }
            val text = view.text as Spannable
            val spans = text.getSpans(0, view.length(), URLSpan::class.java)
            spans.indices.reversed().forEach {
                val oldSpan = spans[it]
                val start = text.getSpanStart(oldSpan)
                val end = text.getSpanEnd(oldSpan)
                val url = oldSpan.url
                text.removeSpan(oldSpan)
                text.setSpan(CustomTabsURLSpan(url), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            }
            return text
        }
        return source
    }

    override fun onFocusChanged(
        view: View?,
        sourceText: CharSequence?,
        focused: Boolean,
        direction: Int,
        previouslyFocusedRect: Rect?
    ) {}
}

Другие вопросы по тегам