Prithniraj Nicyone
Prithniraj Nicyone

Reputation: 5111

AutoLink with hyperLink android

I have a textview which can contain links like https://www.google.com and hyper links with anchor tag Google

Now, I have added the below properties on this textview.

Linkify.addLinks(textview, Linkify.WEB_URLS);
textview.setMovementMethod(LinkMovementMethod.getInstance());

But the links like https://www.google.com these are coming fine in blue and redirecting to the page but anchor tags are not coming in blue and they are not redirecting it.

So, I want to make my textview to render both type of links: direct links and hyper links. How can I do this.

Upvotes: 1

Views: 641

Answers (3)

Paul Hlusko
Paul Hlusko

Reputation: 21

//the string to add links to
val htmlString = "This has anchors and urls http://google.com also <a href=\"http://google.com\">Google</a>."

//Initial span from HtmlCompat will link anchor tags
val htmlSpan = HtmlCompat.fromHtml(htmlString, HtmlCompat.FROM_HTML_MODE_LEGACY) as Spannable

//save anchor links for later
val anchorTagSpans = htmlSpan.getSpans(0, htmlSpan.length, URLSpan::class.java)

//add first span to TextView
textView.text = htmlSpan

//Linkify will now make urls clickable but overwrite our anchor links
Linkify.addLinks(textView, Linkify.ALL)
textView.movementMethod = LinkMovementMethod.getInstance()
textView.linksClickable = true

//we will add back the anchor links here
val restoreAnchorsSpan = SpannableString(textView.text)
for (span in anchorTagSpans) {
    restoreAnchorsSpan.setSpan(span, htmlSpan.getSpanStart(span), htmlSpan.getSpanEnd(span), Spanned.SPAN_INCLUSIVE_INCLUSIVE)
}

//all done, set it to the textView
textView.text = restoreAnchorsSpan

Upvotes: 0

PH88
PH88

Reputation: 1806

It's mentioned in javadoc of Linkify#addLinks(Spannable, Int) that:

...If the mask is nonzero, it also removes any existing URLSpans attached to the Spannable, to avoid problems if you call it repeatedly on the same text.

Although it is not mentioned in Linkify#addLinks(TextView, Int) which you're using, it appears that they follow the same behavior and existing links (i.e. the 'anchor tags' in your question) would be removed before linkify.

To workaround and preserve existing links ('anchor tags' in your case), you need to backup existing spans (i.e. TextView#getText --> convert to Spanned --> use Spanned#getSpans to list existing links --> use Spanned#getSpanStart and Spanned#getSpanEnd and Spanned#getSpanFlags to retrieve the settings of each)

After linkify, re-add the spans (i.e. TextView#getText --> convert to Spannable --> use Spannable#setSpan to re-add the links --> Set the Spannable back with TextView#setText)

Depending on your case, you might also need to check for overlapping 'anchor tags' and 'linkify links' and adjust accordingly...

As you see, this is quite tedious and complex and error prone to code. To simplify things, I have just incorporate all these into Textoo library for reuse and sharing. With Textoo, you can achieve the same by:

TextView myTextView = Textoo
            .config((TextView) findViewById(R.id.view_location_disabled))
            .linkifyWebUrls()
            .apply();

Textoo will preserve exiting links and linkify all non-overlapping web urls.

Upvotes: 0

kris larson
kris larson

Reputation: 30985

Linkify (the way you've invoked it) only knows to convert things that actually look like web URLs (i.e. they begin with http or https, followed by colon and two slashes, etc. etc).

If you want to convert something else into links, you will have to add some more parameters to Linkify to give it more smarts to convert what you want. You can create a MatchFilter and a TransformFilter then call Linkify.addLinks(TextView text, Pattern p, String scheme, Linkify.MatchFilter matchFilter, Linkify.TransformFilter transformFilter)

But it looks to me like you want to take a word like "Google" and add a link for "https://www.google.com". That's not something that can be scanned. For that, you need to use a SpannableStringBuilder. Your code might look something like this:

    String text = "This is a line with Google in it.";
    Spannable spannable = new SpannableString(text);
    int start = text.indexOf("Google");
    int end = start + "Google".length();
    URLSpan urlSpan = new URLSpan("https://www.google.com");
    spannable.setSpan(urlSpan, start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
    textView.setText(spannable);

Upvotes: 1

Related Questions