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 ClickableSpan
s 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
.