Control onclicklistener in autolink enabled textview - android

I am using a TextView for which I have set autolink="web" property in XML file. I have also implemented the onClickListener for this TextView. The problem is, when the text in TextView contains a hyperlink, and if I touch that link, the link opens in browser but simultaneously the onClickListener triggers too. I don't want that.
What I want is, if I touch the hyperlink the clickListener should not fire. It should only fire if I touch the part of the text that is not hyperlinked. Any suggestion?

You can achieve this using a work around in getSelectionStart() and getSelectionEnd() functions of the Textview class,
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ClassroomLog.log(TAG, "Textview Click listener ");
if (tv.getSelectionStart() == -1 && tv.getSelectionEnd() == -1) {
//This condition will satisfy only when it is not an autolinked text
//Fired only when you touch the part of the text that is not hyperlinked
}
}
});
It may be a late reply, but may be useful to those who are searching for a solution.

one of the #CommonsWare post helps to intercept autolink OnClick event.
private void fixTextView(TextView tv) {
SpannableString current = (SpannableString) tv.getText();
URLSpan[] spans =
current.getSpans(0, current.length(), URLSpan.class);
for (URLSpan span : spans) {
int start = current.getSpanStart(span);
int end = current.getSpanEnd(span);
current.removeSpan(span);
current.setSpan(new DefensiveURLSpan(span.getURL()), start, end,
0);
}
}
public static class DefensiveURLSpan extends URLSpan {
private String mUrl;
public DefensiveURLSpan(String url) {
super(url);
mUrl = url;
}
#Override
public void onClick(View widget) {
// openInWebView(widget.getContext(), mUrl); // intercept click event and do something.
// super.onClick(widget); // or it will do as it is.
}
}
Apply above code simply as below. It will go through all linkable texts and replace click events to above event handler.
fixTextView(textViewContent);

You can set the property android:linksClickable="false" in your TextView, in conjuction with android:autoLink="web"; this makes the links visible, but not clickable.

if you wish, you can use the next code which allows to customize the clickable links within the string ( based on this post ) :
usage:
final TextView textView = (TextView) findViewById(R.id.textView);
final Spanned text = Html.fromHtml(getString(...));
textView.setText(text);
textView.setMovementMethod(new LinkMovementMethodExt());
LinkMovementMethodExt.java
public class LinkMovementMethodExt extends LinkMovementMethod {
private static LinkMovementMethod sInstance;
public static MovementMethod getInstance() {
if (sInstance == null)
sInstance = new LinkMovementMethodExt();
return sInstance;
}
#Override
public boolean onTouchEvent(final TextView widget, final Spannable buffer, final MotionEvent event) {
final int action = event.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
final int x = (int) event.getX() - widget.getTotalPaddingLeft() + widget.getScrollX();
final int y = (int) event.getY() - widget.getTotalPaddingTop() + widget.getScrollY();
final Layout layout = widget.getLayout();
final int line = layout.getLineForVertical(y);
final int off = layout.getOffsetForHorizontal(line, x);
final ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
//do something with the clicked item...
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
}

Kotlin version:
Similar to older answers in Java. Simply:
In Layout Editor/XML, add the types of things you'd like to hyperlink via the autoLink property.
<TextView
...
android:autoLink="web|phone|email" />
Add an onClickListener to your TextView in Kotlin code to handle clicks on the plain text part. Check to make sure the person didn't click on a link by checking selectionStart and selectionEnd.
binding.messageText.setOnClickListener { view ->
if (binding.messageText.selectionStart == -1 && binding.messageText.selectionEnd == -1) {
// do whatever you want when they click on the plain text part
}
}

Use textView.getSelectionStart() and textView.getSelectionEnd().If u click any text other than link textView.getSelectionStart() and textView.getSelectionEnd() will be -1 .So by using a if condition in onClickListner you can block the onClick action when link is clicked .
//inside onClickListner
if(textView.getSelectionStart()==-1&&textView.getSlectionEnd==-1){
//onClick action
}

private void fixTextView(TextView tv) {
SpannableString current = (SpannableString) tv.getText();
URLSpan[] spans =
current.getSpans(0, current.length(), URLSpan.class);
for (URLSpan span : spans) {
int start = current.getSpanStart(span);
int end = current.getSpanEnd(span);
current.removeSpan(span);
current.setSpan(new DefensiveURLSpan(span.getURL()), start, end,
0);
}
}
public static class DefensiveURLSpan extends URLSpan {
public final static Parcelable.Creator<DefensiveURLSpan> CREATOR =
new Parcelable.Creator<DefensiveURLSpan>() {
#Override
public DefensiveURLSpan createFromParcel(Parcel source) {
return new DefensiveURLSpan(source.readString());
}
#Override
public DefensiveURLSpan[] newArray(int size) {
return new DefensiveURLSpan[size];
}
};
private String mUrl;
public DefensiveURLSpan(String url) {
super(url);
mUrl = url;
}
#Override
public void onClick(View widget) {
// openInWebView(widget.getContext(), mUrl); // intercept click event and do something.
// super.onClick(widget); // or it will do as it is.
}
}
You would then call fixTextView(textViewContent); on the view after it is declared (via inflation or findViewById) or added to the window (via addView)
This includes the missing requirement to set a CREATOR when extending a Parcelable.
It was proposed as an edit, but rejected. Unfortunately, now future users will have to find out the original one is incomplete first. Nice one, reviewers!

Instead of using a onClickListener, you can try this.
private void addLink() {
tvLink = (TextView) findViewById(R.id.tvInfo2);
String strURL = UrlLoader.getCodeUrl();
// Make the url string clicable and take action in its onclick
SpannableString spanUrl = SpannableString.valueOf(strURL);
spanUrl.setSpan(new InternalURLSpan(new OnClickListener() {
public void onClick(View v) {
//Do Some action
}
}), 0, spanUrl.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tvLink.setText(spanUrl);
// We probably also want the user to jump to your link by moving the
// focus (e.g. using the trackball), which we can do by setting the
// proper movement method:
MovementMethod m = tvLink.getMovementMethod();
if ((m == null) || !(m instanceof LinkMovementMethod)) {
if (tvLink.getLinksClickable()) {
tvLink.setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
Also in the layout XML file , dont forget to add
<TextView android:layout_width="wrap_content" android:linksClickable="true"
android:layout_height="wrap_content" android:id="#+id/tvInfo2" android:text="#string/url_link" />

Just adding
textView.setMovementMethod(CustomLinkMovementMethod.getInstance());
to #binary's answer for those whose the method did not work with them

Related

How can I link some text of a TextView to an Activity?

I would like to link some text on a TextView to an Activity. This is the TextView that I have:
<TextView
android:id="#+id/termsLink"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/terms"
android:layout_weight="4"/>
where #string/terms is:
<string name="terms">Accept terms & conditions..</string>
If I had a link to a webpage I would do it like this:
TextView link = (TextView) findViewById(R.id.termsLink);
link.setMovementMethod(LinkMovementMethod.getInstance());
but I do not know how to start an Activity when I press the link as when it is a real link (that it links a webpage).
EDIT: Please note that I do not have to handle the onClick event in the full text because the link is only on the part "terms & conditions".
EDIT 2: I have tried using two TextView as suggested on the comments and one of the answers below to make the same effect. But sometimes (depending on the screen) the "terms & conditions" part occupy two lines because it does not fill properly on the available space so the second line it is shown on the second TextView and not on the begining of the second line.
The effect is similar to this:
Accept terms &
conditions.
and I would like that it would be like this:
Accept terms &
conditions.
Thanks in advance!
Create a helper class with inner onClick listener
public class ClickSpan extends ClickableSpan {
private String url;
private OnClickListener listener;
public ClickSpan(String url, OnClickListener listener) {
this.url = url;
this.listener = listener;
}
#Override
public void onClick(View widget) {
if (listener != null) listener.onClick(url);
}
public interface OnClickListener {
void onClick(String url);
}
}
Then convert existing span into clickable one
public static Spannable createClickableSpans(Spanned original, ClickSpan.OnClickListener listener) {
SpannableString result = new SpannableString(original);
URLSpan[] spans = result.getSpans(0, result.length(), URLSpan.class);
for (URLSpan span : spans) {
int start = result.getSpanStart(span);
int end = result.getSpanEnd(span);
int flags = result.getSpanFlags(span);
result.removeSpan(span);
result.setSpan(new ClickSpan(span.getURL(), listener), start, end, flags);
}
return result;
}
So, final usage would be like
TextView link = (TextView) findViewById(R.id.termsLink);
link.setMovementMethod(LinkMovementMethod.getInstance());
link.setText(createClickableSpans((Spanned)link.getText(), new ClickSpan.OnClickListener(){
#Override
public void onClick(String url){
//Handle URL on text view click
}
}));
To make only part of a TextView clickable, you can use a spannable inside the TextView and set an onClick event listener. From here, you launch the activity with an intent as usual. You can limit the clickable section of the text by specifying the character positions (start to end)
Checkout this answer by #becomputer06
How to set the part of the text view is clickable
You should probably separate the text into 2 text views one with the terms and condition and one with just the accept.It would make things cleaner and easier. The following TextView is assuming its just for accept.
In the layouts corresponding java class(example: activity_main -> MainActivity):
public void start_activity(View view){
Intent newActivityIntent = new Intent(this,NewActivity.class);
startActivity(newActivityIntent);
}
NewActivity.class is just the name of the activity you want to start.
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
....
}
public void start_activity(View view){
.....
}
}

How to register OnClickListner on hyperlink

I am using a text view in my aap, which is having plane text as well as a hyperlink. Now when I click on hyperlink then link open with default browser. But in actual I dont want to open default browser. Actually I want to register OnClickListener on hyperlink and want to perform other.
I searched on internet and I got this solution...
Control onclicklistener in autolink enabled textview
But this is not helpful for me.
Anyone can tell me that how I can perform this.
Thanks in advance
you can use a Spannable object
final Spannable span = new SpannableString(text);
span.setSpan(new ClickableSpan() {
#Override
public void onClick(View v) {
}
}, 0, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
where text is your hyperlink
Remove android:autoLink="web" if this property setted into XML.
TextView textView =(TextView)findViewById(R.id.textView);
textView.setClickable(true);
when you want to open in browser use this code
textView.setMovementMethod(LinkMovementMethod.getInstance());
String text = "<a href='http://www.google.com'> Google </a>";
textView.setText(Html.fromHtml(text));
if you want to perform some operation register onclick listener for textview and perform.
textView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
Try doing this add
in your
main.xml
<TextView
android:id="#+id/yourTVID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="performSomeAction" />
in your SomeActivity.java
public void performSomeAction( View v){
//Perform your action
}
Try this, it should solve your problem. This method will return a Spannable String which have part of it clickable.
Before calling the below method you should Create CharSequence from the String then convert it to Spannable
CharSequence charSequencce = testView.getText();
Spannable spannable = (Spannable) charSequencce;
public SpannableStringBuilder addClickToPartsOfString(Spannable charSequence, String[] stringsToAddClick, final OnHyperLinkClickListener onClickListener) {
SpannableStringBuilder ssb = new SpannableStringBuilder(charSequence);
for(final String s : stringsToAddClick) {
int index1 = charSequence.toString().indexOf(s);
int index2 = (s.length() + index1);
ssb.setSpan(new ClickableSpan() {
#Override
public void onClick(View widget) {
onClickListener.onClick(s);
}
}, index1, index2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return ssb;
}
I've just made a library aiming to simplify this. See Textoo. You can achieve the same with code like:
TextView locNotFound = Textoo
.config((TextView) findViewById(R.id.view_location_disabled))
.addLinksHandler(new LinksHandler() {
#Override
public boolean onClick(View view, String url) {
if ("internal://settings/location".equals(url)) {
Intent locSettings = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(locSettings);
return true;
} else {
return false;
}
}
})
.apply();
Internally the library converts existing links in your textview / string resources (android system parse html links in string resources into Span for you already) into custom ClickableSpan and capture clicks into calls to your handlers.
This relieve you from having to calculate and hard coding the position of clickable spans to add. Thus make it easier to externalize your text into string resources and better for localization.

ANDROID onTouchListener on button array

I have put a lot of buttons (16*16) in a button array.
The buttons numbers are directly related to changes they should do in another array (e.g. button[12][7] sets the value of stat[12][7] to 1)
So I thought it's possible to put on single line in the onTouch method that reacts to every button.
Example (of course, not working)
public boolean onTouch(View arg0, MotionEvent arg1) {
if (arg1.getAction() == MotionEvent.ACTION_DOWN) {
if(arg0 == button[int a][int b]){stat[a][b]=1};
In this pseudocode, the button would create 2 ints that describe the 2 dimensions of the array which get passed to the stat array.
If anyone had a solution for this, he would save me a few hours this night.
Thanks for your answers.
I think HasMap is a better solution
private HashMap<Integer,Button> btnMap = new HashMap<Integer, Button>();
private void init(){
Button yourFirstBtn = (Button) findViewById(R.id.yourFirstBtn);
btnMap.put(yourFirstBtn.getId(), yourFirstBtn);
for(Button tempBtn: btnMap.values()){
tempBtn.setOnClickListener(this);
}
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Button clickedBtn = btnMap.get(v.getId());
}
Are you adding the onTouchListener to the buttons' container?
Your best bet is to add an onTouchListener to each button, and then arg0 will correspond to the specific button.
Another option would be to use a GridView, which has an setOnItemClickListener you can use. http://developer.android.com/reference/android/widget/GridView.html
As you add each button to the array, set a tag that indicates its indices. Tags are there for adding properties to a view without having to resort to another data structure.
For example:
button[12][7].setTag("12|7");
If your button were pre-defined in XML, you could do the same with:
android:tag="12|7"
Then in the touch listener (I assume the same one is attached to all the buttons), get the tag from the view that was touched:
String tag = (String) view.getTag();
Then substring out and use the two indexes as required:
String indx1 = tag.substring(0, tag.indexOf("|"));
String indx2 = tag.substring(tag.indexOf("|")+1);
stat[Integer.parseInt(indx1)][Integer.parseInt(indx2)] = 1;
Try something like this:
Button[][] myButtonMatrix = new Button[] {
new Button[] { button11, button12, button13, button 14 },
new Button[] { button21, button22, button23, button24 }
};
public class MatrixButtonListener implements View.OnClickListener {
private int x;
private int y;
public MatrixButtonListener(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
#Override
public void onClick(View v) {
stat[x][y] = x-y; // changes were made only in relation to x and y, nothing else
// for example:
if(x == 0) {
// button in first row
// do something
}
}
};
// to apply to each button in matrix:
for(int i=0; i<myButtonMatrix.length; i++) {
for(int j=0; j<myButtonMatrix[i].length; j++) {
myButtonMatrix[i][j].setOnClickListener(new MatrixButtonListener(i,j));
}
}
What this is supposed to do:
Create a generic OnClickListener class, which takes the x and y position as parameter, so each onClickListener has the same behaviour, but differnet x and y positions, depending on the button itself.
Note: This is not tested.
EDIT:
Another way would be a custom button class, which you use, which contains the X/Y coordinates as well. Simply add onClickListener to each button, cast it back to your custom view, and ask for x/y.

Spanned as from Html.fromHtml, but with custom ClickableSpan for custom scheme

I have a TextView that displays some HTML code (images included, ImageGetter).
The html is not mine, but I can ask them to include custom scheme links, maybe even tags.
Purpose: to display some dynamically generated content without the need to play with nested Android layouts.
Problem: some links must be handled in the application (new Fragment loaded).
Can't use a receiver for action.VIEW, since it's an Activity Intent, not a broadcast, and its use will be very contextual, so only a programmatically registered receiver would do.
I'm usingtextView.setText(Html.fromHtml(content.content, imageGetter, null). need everything to remain the same, except some spans should have my own onClick on it. I'm not very familiar with Spanned, so I see these options:
Edit the SpannableStringBuilder returned from Html.fromHtml, and replace the URLSpans I want with a custom ClickableSpan (how?)
As above, but copy everything to a new builder, exchanging the URLSpans for my own (how? append takes a CharSequence only, and I get RelativeSizeSpan, StyleSpan, ImageSpan, URLSpan...)
Create a Spanned manually. I can do it for the custom scheme, but how to duplicate the effect of Html.fromHtml (or close enough) for all else?
[edit]
Thanks to MH. for the info. I had tried that before, but failed. Now that i returned to it, I found i had made an error, passing the wrong item to the 1st argument of setSpan.
If anyone's interested, i now use this:
public static interface OnSpanClickListener {
void onClick(String url);
}
public static SpannableStringBuilder getSpannable(String source, ImageGetter imageGetter, String scheme, final OnSpanClickListener clickHandler){
SpannableStringBuilder b = (SpannableStringBuilder) Html.fromHtml(source, imageGetter, null);
for(URLSpan s : b.getSpans(0, b.length(), URLSpan.class)){
String s_url = s.getURL();
if(s_url.startsWith(scheme+"://")){
URLSpan newSpan = new URLSpan(s_url.substring(scheme.length()+3)){
public void onClick(View view) {
clickHandler.onClick(getURL());
}
};
b.setSpan(newSpan, b.getSpanStart(s), b.getSpanEnd(s), b.getSpanFlags(s));
b.removeSpan(s);
}
}
return b;
}
(...)
body.setText(getSpannable(content.content, imageGetter, getResources().getString(R.string.poster_scheme), new OnSpanClickListener(){
public void onClick(String url) {
// do whatever
}
}));
Option 1 is probably most straightforward and most of the hard work for it has already been done before. You've got the general idea correct: after the HTML has been processed, you can request all the generated URLSpan instances and loop through them. You can then replace it with a customized clickable span to get full controls over any of the span clicks.
In the example below, I'm just replacing every URLSpan with a simple extension of that class that takes the original url (actually, I should probably say 'uri') and replace its scheme part. I've left the actual onClick() logic unimplemented, but I'll leave that up to your imagination.
SpannableStringBuilder builder = ...
URLSpan[] spans = builder .getSpans(0, builder .length(), URLSpan.class);
for (URLSpan span : spans) {
int start = builder .getSpanStart(span);
int end = builder .getSpanEnd(span);
s.removeSpan(span);
span = new CustomURLSpan(span.getURL().replace("http://", "scheme://"));
s.setSpan(span, start, end, 0);
}
textView.setText(builder);
As mentioned earlier, here the CustomURLSpan class is a simple extension of URLSpan that takes a url and overrides the onClick() method so our own logic can be executed there.
public class CustomURLSpan extends URLSpan {
public CustomURLSpan(String url) {
super(url);
}
#Override public void onClick(View widget) {
// custom on click behaviour here
}
}
Some related Q&A's that basically do a similar thing (might be helpful for some more inspiration):
Can I change TextView link text after using Linkify?
Remove underline from links in TextView - Android
As you will use TextView.setMovementMethod(LinkMovementMethod.getInstance()) to make it respond for the partly click, you can implement a customized LinkMovementMethod to intercept the click event and process your own logic.
public class CustomLinkMovementMethod extends LinkMovementMethod {
private HashMap<Class, SpanProxy> spansProxy = new HashMap<>();
public CustomLinkMovementMethod setSpanProxy(Class spanClazz, SpanProxy proxy) {
spansProxy.put(spanClazz, proxy);
return this;
}
public CustomLinkMovementMethod removeSpanProxy(Class spanClazz) {
spansProxy.remove(spanClazz);
return this;
}
#Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
SpanProxy spanProxy = spansProxy.get(ClickableSpan.class);
if(spanProxy != null) {
spanProxy.proxySpan(link[0], widget);
} else {
link[0].onClick(widget);
}
return true;
}
}
}
return super.onTouchEvent(widget, buffer, event);
}
public interface SpanProxy {
void proxySpan(Object span, View widget);
}
}
And used like this:
textView.setMovementMethod(new CustomLinkMovementMethod().setSpanProxy(ClickableSpan.class,
new CustomLinkMovementMethod.SpanProxy() {
#Override
public void proxySpan(Object span, View widget) {
if (span instanceof URLSpan) {
URLSpan urlSpan = (URLSpan) span;
String url = urlSpan.getURL();
// do what you want with the link
// tbd
return;
}
if (span instanceof ClickableSpan) {
((ClickableSpan) span).onClick(widget);
}
}
}));

Format TextView to look like link

I've been using the android:autoLink just fine for formatting links and such, but I need to use android:onClick so I can't use that in this case. The reasoning is that I find it too easy to click on a phone number accidentally, so I'm going to intercept the click with a confirmation Dialog and then call.
Is there an easy way to still make the phone number in my TextView look like a normal clickable link? I poked around the Android source code, but couldn't find any particular style for me to reference.
This is the shortest solution:
final CharSequence text = tv.getText();
final SpannableString spannableString = new SpannableString( text );
spannableString.setSpan(new URLSpan(""), 0, spannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(spannableString, TextView.BufferType.SPANNABLE);
Sadly, the effect of clicking doesn't show up as being clicked on a real url link, but you can overcome it like so:
final CharSequence text = tv.getText();
final SpannableString notClickedString = new SpannableString(text);
notClickedString.setSpan(new URLSpan(""), 0, notClickedString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(notClickedString, TextView.BufferType.SPANNABLE);
final SpannableString clickedString = new SpannableString(notClickedString);
clickedString.setSpan(new BackgroundColorSpan(Color.GRAY), 0, notClickedString.length(),
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
tv.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(final View v, final MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
tv.setText(clickedString);
break;
case MotionEvent.ACTION_UP:
tv.setText(notClickedString, TextView.BufferType.SPANNABLE);
v.performClick();
break;
case MotionEvent.ACTION_CANCEL:
tv.setText(notClickedString, TextView.BufferType.SPANNABLE);
break;
}
return true;
}
});
Another solution is to use Html.fromHtml(...) , where the text inside has links tags ("") .
If you wish for another solution, check this post.
You can create a colors.xml resource file, what contains colors. Please take a look at Colors
If you want to underline your text, then please take a look at this post:
Underline
Don't forget to add android:clickable="true" or setClickable(true) to
your TextViews to make them clickable!
Linkify is a great class, it hunts for complex patterns like URLs, phone numbers, etc and turns them into URLSpans. Rather than re-write the existing regular expressions I extended the URLSpan class and created a method to upgrade only the telephone URLSpans to a custom URLSpan with a confirmation dialog.
First my extended URLSpan class, ConfirmSpan:
class ConfirmSpan extends URLSpan {
AlertDialog dialog;
View mView;
public ConfirmSpan(URLSpan span) {
super(span.getURL());
}
#Override
public void onClick(View widget) {
mView = widget;
if(dialog == null) {
AlertDialog.Builder mBuilder = new AlertDialog.Builder(widget.getContext());
mBuilder.setMessage("Do you want to call: " + getURL().substring(4) + "?");
mBuilder.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
})
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
openURL();
}
});
dialog = mBuilder.create();
}
dialog.show();
}
public void openURL() {
super.onClick(mView);
}
}
Next the method to swap out the different span classes:
private void swapSpans(TextView textView) {
Spannable spannable = (Spannable) textView.getText();
URLSpan[] spans = textView.getUrls();
for(URLSpan span : spans) {
if(span.getURL().toString().startsWith("tel:")) {
spannable.setSpan(new ConfirmSpan(span), spannable.getSpanStart(span), spannable.getSpanEnd(span), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.removeSpan(span);
}
}
}
Finally all you need to do is create a TextView with the autoLink attribute:
android:autoLink="phone"
And remember to call the swapSpans() method. Understand that I wrote this for fun, there may be other methods of doing this but I am unaware of them at the moment. Hope this helps!
To underline your TextView's text, you have to do something like:
final TextView text = (TextView) findViewById(R.id.text);
SpannableString string = new SpannableString("This is the uderlined text.");
string.setSpan(new UnderlineSpan(), 0, string.length(), 0);
text.setText(string);
This should work. Let me know about your progress.
With kotlin extension function (if you don't need the click effect as on a real link)
fun TextView.hyperlinkStyle() {
setText(
SpannableString(text).apply {
setSpan(
URLSpan(""),
0,
length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
},
TextView.BufferType.SPANNABLE
)
}
How to use
yourTextView.hyperlinkStyle()
Have a better answer.This is what i did.
final SpannableString ss = new SpannableString("Click here to verify Benificiary");
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View textView) {
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
};
ss.setSpan(clickableSpan,0,ss.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setHighlightColor(Color.BLUE);
You go anywhere you like when user clicks on the link through onclick method of ClickableSpan
Simply underline it:
val myText = "Text to be underlined"
textView.text = Html.fromHtml("<u>$myText</u>")
or with kotlin extensions:
fun TextView.underline() {
text = Html.fromHtml("<u>${text}</u>")
}
usage:
textView.text = myText
textView.underline()
More ways to style text in android here: https://medium.com/androiddevelopers/spantastic-text-styling-with-spans-17b0c16b4568

Categories

Resources