Android Textview with Clickable Links: How to Capture Clicks

Android TextView with Clickable Links: how to capture clicks?

Based upon another answer, here's a function setTextViewHTML() which parses the links out of a HTML string and makes them clickable, and then lets you respond to the URL.

protected void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span)
{
int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span);
ClickableSpan clickable = new ClickableSpan() {
public void onClick(View view) {
// Do something with span.getURL() to handle the link click...
}
};
strBuilder.setSpan(clickable, start, end, flags);
strBuilder.removeSpan(span);
}

protected void setTextViewHTML(TextView text, String html)
{
CharSequence sequence = Html.fromHtml(html);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class);
for(URLSpan span : urls) {
makeLinkClickable(strBuilder, span);
}
text.setText(strBuilder);
text.setMovementMethod(LinkMovementMethod.getInstance());
}

Capture http link click event in android textview


public static void setLinkclickEvent(TextView tv, HandleLinkClickInsideTextView clickInterface) {
String text = tv.getText().toString();
String str = "([Hh][tT][tT][pP][sS]?:\\/\\/[^ ,'\">\\]\\)]*[^\\. ,'\">\\]\\)])";
Pattern pattern = Pattern.compile(str);
Matcher matcher = pattern.matcher(tv.getText());
while (matcher.find()) {
int x = matcher.start();
int y = matcher.end();
final android.text.SpannableString f = new android.text.SpannableString(
tv.getText());
InternalURLSpan span = new InternalURLSpan();
span.setText(text.substring(x, y));
span.setClickInterface(clickInterface);
f.setSpan(span, x, y,
android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(f);
}
tv.setLinksClickable(true);
tv.setMovementMethod(LinkMovementMethod.getInstance());
tv.setFocusable(false);
}

public static class InternalURLSpan extends android.text.style.ClickableSpan {

private String text;
private HandleLinkClickInsideTextView clickInterface;

@Override
public void onClick(View widget) {
getClickInterface().onLinkClicked(getText());
}

public void setText(String textString) {
this.text = textString;
}

public String getText() {
return this.text;
}

public void setClickInterface(HandleLinkClickInsideTextView clickInterface) {
this.clickInterface = clickInterface;
}

public HandleLinkClickInsideTextView getClickInterface() {
return this.clickInterface;
}

}

public interface HandleLinkClickInsideTextView {
public void onLinkClicked(String url);
}

After this i just used the method send click event.

textview.setText("http://google.com is google website and http://youtube.com is youtube site");
setLinkclickEvent(textview, new HandleLinkClickInsideTextView() {
public void onLinkClicked(String url) {
// Here I added my code
}
});

How to make links in a TextView clickable

Buried in the API demos, I found the solution to my problem:

File Link.java:

    // text2 has links specified by putting <a> tags in the string
// resource. By default these links will appear but not
// respond to user input. To make them active, you need to
// call setMovementMethod() on the TextView object.

TextView t2 = (TextView) findViewById(R.id.text2);
t2.setMovementMethod(LinkMovementMethod.getInstance());

I removed most of the attributes on my TextView to match what was in the demo.

<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/txtCredits"/>

That solved it. It is pretty difficult to uncover and fix.

Important: Don't forget to remove autoLink="web" if you are calling setMovementMethod().

Android TextView with Clickable Links: how to capture clicks in CustomAdapter ListView?

I solved my problem by adding following line before calling setTextViewHTML():

holder.announcement.setMovementMethod(LinkMovementMethod.getInstance());

So now my getView() method looks like:

if(ann.message.contains("<a href=")){
holder.announcement.setMovementMethod(LinkMovementMethod.getInstance());
setTextViewHTML(holder.announcement, ann.message);
}

TextView catch clicking on link when autoLink is set to web

Actually,

I solved this by abandoning autolLink='web' and by parsing html url, creating SpannableString and setting additional spans.

So, let's say that I want to do the following:

  • if user clicks on the part of the text of textView which is not url, method someMethod() should be called
  • if user clicks on the part of the text of textView which is url, method someMethod() should be called and browser should be openned with given URL

So, first we have the content which is in the variable message and method String extractFirstLink(String text) will be used to get the url.

private static String extractFirstLink(String text) {
Matcher m = Patterns.WEB_URL.matcher(text);
return m.find() ? m.group() : null;
}

Note: in my case I know that I will have only one url, but if you can expect more than one url, this solution (found somewhere on StackOverflow, can't find it right now) will do the work:

public static String[] extractLinks(String text) {
List<String> links = new ArrayList<String>();
Matcher m = Patterns.WEB_URL.matcher(text);
while (m.find()) {
String url = m.group();
links.add(url);
}
return links.toArray(new String[links.size()]);
}

So, here is the code:

int contentTextColor = ...; // color of non-url text in textView
int urlTextColor = ...;
String message = notification.getMessage(); // content stored
final String foundLink = extractFirstLink(message);
SpannableString styledString = new SpannableString(message);

if (foundLink != null) {
int startPosition = message.indexOf(foundLink);
int endPosition = startPosition + foundLink.length();
styledString.setSpan(new ForegroundColorSpan(urlTextColor), startPosition, endPosition, 0);

ClickableSpan clickableURLSpan = new ClickableSpan() {
@Override
public void onClick(View widget) {
someMethod();
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(foundLink));
widget.getContext().startActivity(browserIntent);
}
};

ClickableSpan clickableNonURLSpan1 = new ClickableSpan() {
@Override
public void onClick(View view) {
someMethod();
}

@Override
public void updateDrawState(TextPaint ds) {
ds.setUnderlineText(false);
}
};
ClickableSpan clickableNonURLSpan2 = new ClickableSpan() {
@Override
public void onClick(View view) {
someMethod();
}

@Override
public void updateDrawState(TextPaint ds) {
ds.setUnderlineText(false);
}
};
styledString.setSpan(clickableURLSpan, startPosition, endPosition, 0);
if (startPosition > 0) {
styledString.setSpan(clickableNonURLSpan1, 0, startPosition - 1, 0);
styledString.setSpan(new ForegroundColorSpan(contentTextColor), 0, startPosition -1, 0);
}
if (endPosition < message.length() -1) {
styledString.setSpan(clickableNonURLSpan2, endPosition + 1, message.length(), 0);
styledString.setSpan(new ForegroundColorSpan(contentTextColor), endPosition + 1, message.length(), 0);
}

txtView.setMovementMethod(LinkMovementMethod.getInstance());
}

txtView.setText(styledString);

There are some interesting things here. For example, when I wish to make span responsive to click, I have to use ClickableSpan, but! I must handle situation where I have format text1-url-text2. So, since all these three parts should be ClickableSpans and text1 and text2 should not have underline, which is the default behaviour of it, I had to override updateDrawState method in my implementation of ClickableSpan for text1 and text2.

There is another catch, I had to create two implementation of ClickableSpan interface in order to have to work as intended. That's why I created clickableNonURLSpan1 and clickableNonURLSpan2.

How to intercept click on link in TextView?

There's this method: https://stackoverflow.com/a/3452944/1799219

All it's really doing is passing the link to your own activity (as links are normally passed to other activities) and then you extract the URL.

handle textview link click in my android app

Coming at this almost a year later, there's a different manner in which I solved my particular problem. Since I wanted the link to be handled by my own app, there is a solution that is a bit simpler.

Besides the default intent filter, I simply let my target activity listen to ACTION_VIEW intents, and specifically, those with the scheme com.package.name

<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW" />
<data android:scheme="com.package.name" />
</intent-filter>

This means that links starting with com.package.name:// will be handled by my activity.

So all I have to do is construct a URL that contains the information I want to convey:

com.package.name://action-to-perform/id-that-might-be-needed/

In my target activity, I can retrieve this address:

Uri data = getIntent().getData();

In my example, I could simply check data for null values, because when ever it isn't null, I'll know it was invoked by means of such a link. From there, I extract the instructions I need from the url to be able to display the appropriate data.

How to have a clickable link in a textview, within a custom listview and still have clickable listview

ListView with focusable elements disable the click event on the ListView itself

To overcome it..

Add :

android:descendantFocusability="blocksDescendants"

to your listview row's root layout

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical">


<TextView
android:id="@+id/textview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:focusable="false"
android:textSize="15sp" />
</LinearLayout>


Related Topics



Leave a reply



Submit