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.
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);
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.
//the string to add links to
val htmlString = "This has anchors and urls http://google.com also Google."
//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
Related
Let’s say you have the string:
"https://google.com to go to google. https://amazon.com to go to Amazon."
In a TextView, how would you replace the url’s with a link that shows “Click here” (or “Haz clic aquí” in spanish) and would take you to the correct url?
Keep in mind that the text is dynamic, it’s retrieved from the API, and there is no way to know if or how many links may be in any given post.
The finished product should look like this:
“Click here to go to google. Click here to go to Amazon.”
After many many hours…
Here is my solution.
I put this code inside the RecyclerView adapter's onBindViewHolder().
// replace url links with clickable link that says "Click here" (or "Haz clic aquí" in Spanish).
// link color is set in TextView in the xml.
// SpannableStringBuilder is mutable, so we can replace the link.
SpannableStringBuilder spannableStringBuilder = new
SpannableStringBuilder(newsFeedItem.getBody());
// use Linkify to automatically set all Url's in the string.
Linkify.addLinks(spannableStringBuilder,Linkify.WEB_URLS);
//do this process for each Url
for (URLSpan urlSpan: spannableStringBuilder.getSpans(0,spannableStringBuilder.length(),URLSpan.class)){
int start = spannableStringBuilder.getSpanStart(urlSpan);
int end = spannableStringBuilder.getSpanEnd(urlSpan);
// put whatever you want it to say into the next line where I wrote "Click here".
SpannableString customLinkSpannableString = new SpannableString("Click here");
customLinkSpannableString.setSpan(urlSpan,0, customLinkSpannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannableStringBuilder.replace(start, end, customLinkSpannableString);
}
// now set the fixed up string into the TextView and set LinkMovementMethod.
textView.setText(spannableStringBuilder);
textView.setMovementMethod(LinkMovementMethod.getInstance());
A number of discussions on here going back years related to getting hyperlinks to work in a TextView. The conclusion is that autoLink works for parsing out URLs that are simply embedded in the text, e.g., "go to www.google.com". Then there is
setMovememtMethod(LinkMovementMethod.getInstance());
that will cause actual HTML tags to work, e.g. go to Google. However, using the latter causes autoLink to not work in the same view.
My issue is that I am displaying text that is supplied by a user database, so I have no control over the formatting. In some cases, this text has plaintext links while in others it is entered as HTML tags. Is there any way to get both types of links to work at the same time?
Both plain text links & links with HTML tags will work with the below code
TexView in xml
<TextView
android:id="#+id/txt_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textColorLink="#06b" />
Here in activity.java
String text = "this is the link with anchor tag Google. here is the plain text link http://www.google.com";
TextView textView = (TextView) findViewById(R.id.txt_view);
textView.setText(getParsedLinks(text));
textView.setMovementMethod(LinkMovementMethod.getInstance());
instead of using android:autoLink="all" in xml or Linkify.addLinks(textView, Linkify.ALL) use Linkify.addLinks to SpannableString as in below method
SpannableString getParsedLinks(String txt){
Spanned span = Html.fromHtml(txt);
URLSpan[] urlSpans = span.getSpans(0, span.length(), URLSpan.class);
SpannableString s = new SpannableString(span);
Linkify.addLinks(s, Linkify.ALL);
for (URLSpan urlSpan : urlSpans) {
s.setSpan(urlSpan, span.getSpanStart(urlSpan), span.getSpanEnd(urlSpan), 0);
}
return s;
}
This question already has answers here:
How to make normal links in TextView clickable?
(5 answers)
Closed 6 years ago.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="legalText">
By using this xxxxxxxxxxx app, I agree to the Terms of Use and Notice of Privacy Policy [[need official name]] in this app. I understand that use of this xxxxxxxxx app is at my own risk and discretion. I understand and agree that the health information I give to xxxxxxx in this app is truthful and will be the only source of health information used by the xxxxxxxxxx providers during the course of my evaluation and treatment through xxxxxxxxxx. Also, as part of my use of the xxxxxxxx app, I agree that I will not use this app for any purpose that is prohibited by the xxxxxxxx Terms of Use [[link to Terms]] and Consent to Telehealth [[Link to Consent to Telehealth]]”, and Consent to Request Medical Services [insert link to Consent to Request Medical Services].
</string>
</resources>
I need to put links to other xml pages and html pages at bracket locations in this xml file. How do I do that?
Here's what you can do:
Break that one string into several string resources (atleast separate the app-name and links to a different string resource.
Contruct the full legalText by joining the substrings found in step 1. Use the <a href= "link"><a/> tag for the substrings with link. You can style the rest of the substrings accordingly, as you get the idea.
Use the Html.fromHtml method to show the formatting:
Spannable text = (Spannable)Html.fromHtml(legalText);
//this one here to get the links clickable:
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(text);
You might need to get rid of extra underlines at this point, therefore use this method:
private void stripUnderlines(TextView textView) {
Spannable s = (Spannable)textView.getText();
URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class);
for (URLSpan span: spans) {
int start = s.getSpanStart(span);
int end = s.getSpanEnd(span);
s.removeSpan(span);
span = new URLSpanNoUnderline(span.getURL());
s.setSpan(span, start, end, 0);
}
textView.setText(s);
}
As far as i know, it is not possible to add links directly into strings, but you can create different strings and assemble your text with different TextViews and set OnClickListeners and a link-style to the TextViews you want to add link.
If you develop in java and Android Studio, you only have to set an onClickListener on the TextView the same way you do for a button.
You should also add styles such as underline or Color to let the user know there is a link.
I am trying to get a textview to process a hyperlink as well as phone numbers. Say my text is:
"555-555-555, www.google.com, Google!"
If I run Html.fromHtml() on this string, then the TextView shows Google! correctly as a clickable link but not the other two.
If I run Linkify.addLinks(TextView, Linkify.All) on the TextView, then the first two are correctly recognized as a phone number and url, but the html is not processed in the last one.
If I run both of them, then either one or the other is honored, but not both at the same time. (Html.fromHtml will remove the html tags there, but it won't be a link if linkify is called after)
Any ideas on how to get both of these functions to work simultaneously? So all the links are processed correctly? Thanks!
Edit: Also, the text is changed dynamically so I'm not sure how I would be able to go about setting up a Linkify pattern for that.
It's because Html.fromHtml and Linkify.addLinks removes previous spans before processing the text.
Use this code to get it work:
public static Spannable linkifyHtml(String html, int linkifyMask) {
Spanned text = Html.fromHtml(html);
URLSpan[] currentSpans = text.getSpans(0, text.length(), URLSpan.class);
SpannableString buffer = new SpannableString(text);
Linkify.addLinks(buffer, linkifyMask);
for (URLSpan span : currentSpans) {
int end = text.getSpanEnd(span);
int start = text.getSpanStart(span);
buffer.setSpan(span, start, end, 0);
}
return buffer;
}
try to set movement method on your textview instead of using Linkify:
textView.setMovementMethod(LinkMovementMethod.getInstance());
In your TextView's xml layout, you should add the following:
android:autoLink="all"
android:linksClickable="true"
Then you should remove your Linkify code in Java.
It works somehow, but I dont know why. I added a question to see if someone can explain the behavior: Using Linkify.addLinks combine with Html.fromHtml
I have a block of text coming from a webservice, and depending on some tags which I have predefined, I want to style the text before setting it to my TextView. For bold, italics, and underline, I was able to do this easily with the replaceAll command:
PageText = PageText.replaceAll("\\*([a-zA-Z0-9]+)\\*", "<b>$1</b>");
PageText = PageText.replaceAll("=([a-zA-Z0-9]+)=", "<i>$1</i>");
PageText = PageText.replaceAll("_([a-zA-Z0-9]+)_", "<u>$1</u>");
txtPage.setText(Html.fromHtml(PageText), TextView.BufferType.SPANNABLE);
So, to bold a word, surround it with *'s, for italics, surround with _.
But, for strikethrough, Html.fromHtml does not support the "strike" tag, so it can't be done this same way. I've seen examples of using Spannable to set the styling on one section of text, but it requires positional numbers. So, I guess I could loop through the text, searching for - (the tag to represent the strike), then searching for the next one, spanning the text in between, and repeating for all such strings. It will end up being 10 lines of looping code as opposed to 1 for the others, so I'm wondering if there is a more elegant solution out there.
If it is just TextView you can strike through using paint flags
TextView tv=(TextView) v.findViewById(android.R.id.text1);
tv.setPaintFlags(tv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
#Suresh solution works if you want to strikethrough the entire TextView but if you want to strikethrough only some portions of the text then use the code below.
tvMRP.setText(text, TextView.BufferType.SPANNABLE);
Spannable spannable = (Spannable) tvMRP.getText();
spannable.setSpan(new StrikethroughSpan(), 3, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Here text is the text which we want out TextView to display, 3 is the no. of characters (starting from 0) from where the strikethrough will start.
You can do it with a custom TagHandler such as the one on this SO question:
Spanned parsed = Html.fromHtml(PageText, null, new MyHtmlTagHandler());
And the TagHandler implements the methods:
public void handleTag(boolean opening, String tag, Editable output,
XMLReader xmlReader) {
if(tag.equalsIgnoreCase("strike") || tag.equals("s")) {
processStrike(opening, output);
}
}
....
Are you sure Html.fromHtml doesn't support <strike>? It's listed in this Commonsware blog post
It looks like is not really supported, at least it does not work on Android 3.1.
#RMS2 if text is small you can split it into two or three separate text views and apply flag only to the one which you want, not perfect for long texts ;(
Most of the applications we work in are going to use text somewhere throughout the project and thankfully, KTX provides some extension functions when it comes to these parts. For text, we essentially have some functions available for the SpannableStringBuilder class.
For example, after instantiating a Builder instance we can use the build methods to append some bold text:
textView.text =buildSpannedString {
strikeThrough {
append(
value ?: ""
)
}
}