The onClick() of ClickableSpan is not working for URLSpan? - android

In a TextView, I want to popup a toast whenever a hyperlink is clicked, instead of opening the corresponding url in a browser. I use the following code, but the problem here is the onClick() method seems never be called!!:
String source = "link ";
// Get SpannableStringBuilder object from HTML code
CharSequence sequence = Html.fromHtml(source, imgGetter, null);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
// Get an array of URLSpan from SpannableStringBuilder object
URLSpan[] urlSpans = strBuilder.getSpans(0, strBuilder.length(), URLSpan.class);
// Add onClick listener for each of URLSpan object
for (final URLSpan span : urlSpans) {
int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span);
strBuilder.setSpan(new ClickableSpan()
{
#Override
public void onClick(View widget) {
Toast toast = Toast.makeText(context, "well done! you click " + span.getURL(), Toast.LENGTH_SHORT);
toast.show();
}
}, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
TextView t4 = (TextView) findViewById(R.id.text4);
t4.setText(strBuilder);
// No action if this is not set
t4.setMovementMethod(LinkMovementMethod.getInstance());
Can anyone tell me what's wrong with my code and how to fix it? Thanks.

Actually my senior figured out, we need to remove the original URLSpan before adding our own spans using setSpan()
// The original URLSpan needs to be removed to block the behavior of browser opening
strBuilder.removeSpan(span);
Thanks Damian.

Related

Android autolinks: Skip numbers having less than 10 digits

I have a textview with autoLinks set to all. I want to skip numbers like "2018"
which are years, these numbers should not be highlighted. Is there a delimiter I can use in the text so that it skips those numbers while parsing?
Edit:
This issue happens only in Mi devices.
try this....
String s1="jan 2018,Saturday";
String replaceString=s1.replace("2018","");//replaces all occurrences of "2018" to ""
System.out.println(replaceString);
Output := jan ,Saturday.
Use Spanable String in this case to highlight Specific String.
Here is an example:
SpannableString spannableStr = new SpannableString(originalText);
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED);
spannableStr.setSpan(foregroundColorSpan, 15, 30, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
spannableTextView.setText(spannableStr);
Set color and starting string index and ending index.
For more detail check this link click this link
I searched for your answer try this
private void stripUnderlines(TextView textView) {
Spannable s = new SpannableString(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);
}
This requires a customized version of URLSpan which doesn't enable the TextPaint's "underline" property:
private class URLSpanNoUnderline extends URLSpan {
public URLSpanNoUnderline(String url) {
super(url);
}
#Override public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
}
here is the link
Try This Code :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
highlightTv();
}
protected void highlightTv(){
// Specify the text/word to highlight inside TextView
String textToHighlight = "2018";
// Construct the formatted text
String replacedWith = "<font color='green'>" + textToHighlight + "</font>";
// Get the text from TextView
String originalString = textView.getText().toString();
// Replace the specified text/word with formatted text/word
String modifiedString = originalString.replaceAll(textToHighlight,replacedWith);
// Update the TextView text
mTextView.setText(Html.fromHtml(modifiedString));
}

TextView with Html.fromHtml format issue

I've a TextView that will receive some html formatted text like:
<p class="p1"><span class="s1"><strong>Name</strong> Mr. A</span></p>
<p class="p1"><span class="s1"><strong>Place:</strong> Somewhere over the rainbow...</span></p>
I'm using this code:
CharSequence sequence = Html.fromHtml(html);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
text.setText(strBuilder);
Ended up with:
Name: Mr. A\n\nPlace: Somewhere over the rainbow\n\n
Problem, I don't want "\n\n" I just want one "\n", so I've done this:
sequence = sequence.toString().replaceAll("\n\n", "\n");
Ended up with:
Name: Mr. A\nPlace: Somewhere over the rainbow\n
And to remove the last "\n":
try {
int i = sequence.toString().lastIndexOf("\n");
sequence = new StringBuilder(sequence).replace(i, i + 1, "").toString();
} catch (Exception e) {
e.printStackTrace();
}
Ended up with:
Name: Mr. A\nPlace: Somewhere over the rainbow
Perfect just like I wanted, but now all the HTML format is gone.
How can I solve this situation?
Thanks.
EDIT 1:
User Bas van Stein suggested I should remove StringBuilder, but I didn't post all the code. So, I use a StringBuilder because if the text contains an URL I do something like this (complete code):
CharSequence sequence = Html.fromHtml(html);
sequence = sequence.toString().replaceAll("\n\n", "\n");
try {
int i = sequence.toString().lastIndexOf("\n");
sequence = new StringBuilder(sequence).replace(i, i + 1, "").toString();
} catch (Exception e) {
e.printStackTrace();
}
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class);
for (URLSpan span : urls) {
makeLinkClickable(context, strBuilder, span, color);
}
text.setText(strBuilder);
makeLinkClickable method:
private void makeLinkClickable(final Context context, SpannableStringBuilder strBuilder, final URLSpan span, int color) {
int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span);
strBuilder.setSpan(new ClickableSpan() {
#Override
public void onClick(View widget) {
...
}
}, start, end, flags);
strBuilder.setSpan(new ForegroundColorSpan(color), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
strBuilder.removeSpan(span);
}
EDIT 2:
Ok so I figured out what is causing the loss of the format information, is the fact that I'm ignoring the Spanned text converted from Html.fromHtml(html). I guess I'll have to remove the "\n\n" and the last "\n" without losing the Spanned object with all the Span styles, etc. Working on it...
The problem is that you use a StringBuilder, this is not needed at all. You can just set the text as html like this:
myTextView.setText(Html.fromHtml("<h2>Title</h2><br><p>Description here</p>"));
So just remove the string builder and you should get what you want.
EDIT Ok, after your updated question, I have one more suggestion:
What happens when you replace the \n before you pass it to Html.fromHtml().
Might work..

Handling Multiple ClickableSpan in a TextView

I've been stuck at this problem for long. What I'm having is a simple string "This is a link and this is another link". I want to have both "link" words click-able, having different URLs to open in browser.
The simplest way I can do is to set Click-able Span on both "link"
words with different URLs, but the problem I'm facing is finding the
start and end positions of the span. The text is dynamic, and I have
to programmatically find the positions.
One approach would be to find the first occurrence of the word
'link', find the start and end positions and set the span, and then
the second occurrence. But that is not reliable. The text may contain
more than one kind of repeated words, like "This is a cat link and
this is another cat link". Here I have to link both "cat" and "link"
words with different URLs via Click-able Span. How do I go about it?
Try in this manner
String s="Cat link 1 Cat link 2 Cat link 3";
SpannableString ss = new SpannableString(s);
String first ="Cat link 1";
String second ="Cat link 2";
String third ="Cat link 3";
int firstIndex = s.toString().indexOf(first);
int secondIndex = s.toString().indexOf(second);
ClickableSpan firstwordClick = new ClickableSpan() {
#Override
public void onClick(View widget) {
///............
}
};
ClickableSpan secondwordClick = new ClickableSpan() {
#Override
public void onClick(View widget) {
///............
}
};
ss.setSpan(firstwordClick,firstIndex, firstIndex+first.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ss.setSpan(secondwordClick,secondIndex, secondIndex+second.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setLinksClickable(true);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(ss,BufferType.SPANNABLE);
If you cannot programmatically find the difference in the links, then you cannot expect anything else to be able to do it. As the developer, you need a system.
You need to be able to identify the clickable spans - since the links are unique, the text that identifies them must also be unique. This would be a problem for your users, most likely.
You can get an ordered list of URLs and then if the links are indistinguishable, simply use them in the order you receive. Or, you need to change the rules of creating the links or the order in which they are displayed.
One simple way to do this would be to include an identifier before the link say /*/ then using this find the start and end position for link. Once you have that first replace the identifier with a "" and then click away.
I have string something such "you order with orderId {b1j2gh4b} has been claimed by bla bla sotre with phone number (1234124124)"
I am using these braces so as to find out the index of of orderID and Phone number
String notificationMessage = mArrListNotification.get(position).getMessage();
boolean isPhoneNumberAvailable = false, isOrderIdAvailable = false;
int phoneStartIndex = 0, phoneEndIndex = 0, orderIdStartIndex = 0, orderIdEndIndex = 0;
//getting index on the basis of braces added to text
if (notificationMessage.contains("(")) {
isPhoneNumberAvailable = true;
phoneStartIndex = notificationMessage.indexOf("(");
phoneEndIndex = notificationMessage.indexOf(")");
}
if (notificationMessage.contains("{")) {
orderIdStartIndex = notificationMessage.indexOf("{");
orderIdEndIndex = notificationMessage.indexOf("}");
}
// we got the index so remove braces
notificationMessage = notificationMessage.replace("(", " ");
notificationMessage = notificationMessage.replace(")", " ");
notificationMessage = notificationMessage.replace("{", " ");
notificationMessage = notificationMessage.replace("}", " ");
viewHolder.txtNotificationMessage.setText(notificationMessage, TextView.BufferType.SPANNABLE);
Spannable mySpannablePhoneNumber = (Spannable) viewHolder.txtNotificationMessage.getText();
Spannable mySpannableOrderID = (Spannable) viewHolder.txtNotificationMessage.getText();
ClickableSpan mySpanPhoneClick = new ClickableSpan() {
#Override
public void onClick(View widget) {
currentPosition = (Integer) widget.getTag();
String message = mArrListNotification.get(currentPosition).getMessage();
int startIndex = message.indexOf("(");
int endIndex = message.indexOf(")");
phoneNumber = message.substring(startIndex + 1, endIndex);
Log.i("Phone Number", phoneNumber clicked)
}
};
ClickableSpan mySpanOrderClick = new ClickableSpan() {
#Override
public void onClick(View widget) {
currentPosition = (Integer) widget.getTag();
String message = mArrListNotification.get(currentPosition).getMessage();
int startIndex = message.indexOf("{");
int endIndex = message.indexOf("}");
String orderID = message.substring(startIndex + 1, endIndex);
// Log.i("Order id", orderID clicked)
}
};
if (isPhoneNumberAvailable) {
mySpannablePhoneNumber.setSpan(mySpanPhoneClick, phoneStartIndex + 1, phoneEndIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (isOrderIdAvailable) {
mySpannableOrderID.setSpan(mySpanOrderClick, orderIdStartIndex + 1, orderIdEndIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}

How to Remove Underline from hyperlink's text in android ?

I have Button and its text, I retrive it from string.xml i.e.
I have declared a Button text in res/values in strings.xml like
<string name="Google">Google</string>
I removed its text color from blue to white but how do I remove its underline?
in my .java file I am using only setMovementMethod(LinkMovementMethod.getInstance()); to make the link clickabale... I didn't use Linkify, webview or anything like form.Html...
everything works fine. I just want to remove the underline below that "Google" text...
Is there any way to do this in the xml?
I even used android:autoLink="all". But when I used that, the text and button color changes and I dont want that.
Please Help.
TextView text=(TextView) findViewById(R.id.text);
String value = "<html> click to go <font color=#757b86><b>google</b></font> </html>";
Spannable spannedText = (Spannable)
Html.fromHtml(value);
text.setMovementMethod(LinkMovementMethod.getInstance());
Spannable processedText = removeUnderlines(spannedText);
text.setText(processedText);
here is your removeUnderlines()
public static Spannable removeUnderlines(Spannable p_Text) {
URLSpan[] spans = p_Text.getSpans(0, p_Text.length(), URLSpan.class);
for (URLSpan span : spans) {
int start = p_Text.getSpanStart(span);
int end = p_Text.getSpanEnd(span);
p_Text.removeSpan(span);
span = new URLSpanNoUnderline(span.getURL());
p_Text.setSpan(span, start, end, 0);
}
return p_Text;
}
also create class URLSpanNoUnderline.java
import co.questapp.quest.R;
import android.text.TextPaint;
import android.text.style.URLSpan;
public class URLSpanNoUnderline extends URLSpan {
public URLSpanNoUnderline(String p_Url) {
super(p_Url);
}
#Override
public void updateDrawState(TextPaint p_DrawState) {
super.updateDrawState(p_DrawState);
p_DrawState.setUnderlineText(false);
p_DrawState.setColor(R.color.info_text_color);
}
}
using this line you can also change the color of that text p_DrawState.setColor(R.color.info_text_color);
Kotlin has Textview extension for removing underline
fun TextView.removeLinksUnderline() {
val spannable = SpannableString(text)
for (urlSpan in spannable.getSpans(0, spannable.length, URLSpan::class.java)) {
spannable.setSpan(object : URLSpan(urlSpan.url) {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.isUnderlineText = false
}
}, spannable.getSpanStart(urlSpan), spannable.getSpanEnd(urlSpan), 0)
}
text = spannable
}
Usage:
txtView.removeLinksUnderline()
after trying a lot finally i found the solution.
I removed the link from string.xml
and added this code in my java file.
Button btnGoogle = ( Button GoogleAlert.findViewById(
R.id.btnGoogle );
btnGoogle.setMovementMethod(
LinkMovementMethod.getInstance() );
btnGoogle.setOnClickListener( new OnClickListener()
{
#Override
public void onClick( View v )
{
Uri uri = Uri.parse(
"http://www.google.com" );
Intent intent = new Intent( Intent.ACTION_VIEW, uri );
startActivity( intent );
buyAlert.dismiss();
}
} );
and it worked perfectly.
You add style=\"text-decoration:none\" to your <a> tag.
For more information on how your string resources should be formatted, check out the String Resources Documentation.
TextView text=(TextView) findViewById(R.id.text);
final String s = text.getText();
text.setText("");
text.setText(s);
that's all, folks ))

Android: Launch activity from clickable text

Is there any way I can launch an activity from a portion of a string.
eg
I have this in my strings.xml file:
<string name="clickable_string">This is a <u>clickable string</u></string>
I would like the text between the u tags to be underlined and launch an activity when clicked when inserted in to a TextView
Try this,
final Context context = ... // whereever your context is
CharSequence sequence = Html.fromSource(context.getString(R.string.clickable_string));
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
UnderlineSpan[] underlines = strBuilder.getSpans(UnderlineSpan.class);
for(UnderlineSpan span : underlines) {
int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span);
ClickableSpan myActivityLauncher = new ClickableSpan() {
public void onClick(View view) {
context.startActivity(getIntentForActivityToStart());
}
};
strBuilder.setSpan(myActivityLauncher, start, end, flags);
}
TextView textView = ...
textView.setText(strBuilder);
textView.setMovementMethod(LinkMovementMethod.getInstance());
Basically you have to attach a Span object to the range of characters you want to be clickable. Since you are using HTML anyways, you can use the underline spans placed by the Html.fromSource() as markers for your own spans.
Alternatively you could also define a Tag within the string that only you know of.
i.e. <activity>
And supply your own tag handler to the Html.fromSource() method. This way your TagHandler instance could do something like, surround the tagged text with a specific color, underline, bold and make it clickable. However I would only recommend the TagHandler approach if you find yourself writing this type of code a lot.
assign this string to one of your xml layout and then in your code get the id of TextView and then implement OnClickListener for this Textview,inside of it you can start your new activity you want.
Answered here Make parts of textview clickable (not url)
I just made a modification if you want to use it with a HTML Message do the following
In your Display function
public void displayText(String message) {
chapterTextView.setText(Html.fromHtml(message),TextView.BufferType.SPANNABLE);
chapterTextView.setMovementMethod(LinkMovementMethod.getInstance());
Spannable clickableMessage = (Spannable) chapterTextView.getText();
chapterTextView.setText(addClickablePart(clickableMessage), BufferType.SPANNABLE);
}
The Modified function of addClickablePart
private SpannableStringBuilder addClickablePart(Spannable charSequence) {
SpannableStringBuilder ssb = new SpannableStringBuilder(charSequence);
int idx1 = charSequence.toString().indexOf("(");
int idx2 = 0;
while (idx1 != -1) {
idx2 = charSequence.toString().indexOf(")", idx1) + 1;
final String clickString = charSequence.toString().substring(idx1, idx2);
ssb.setSpan(new ClickableSpan() {
#Override
public void onClick(View widget) {
Toast.makeText(getActivity(), clickString,
Toast.LENGTH_SHORT).show();
}
}, idx1, idx2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
idx1 = charSequence.toString().indexOf("(", idx2);
}
return ssb;
}
Hope this help someone.

Categories

Resources