Linkify
Android
Linkify
Linkify
take a piece of text and a regular expression and turns all of the
regex matches in the text into clickable links. This is particularly
useful for matching things like email addresses, web urls, etc. and
making them actionable. Alone with the pattern that is to be matched,
a url scheme prefix is also required. Any pattern match that does not
begin with the supplied scheme will have the scheme prepended to the
matched text when the clickable url is created. For instance, if you
are matching web urls you would supply the scheme
http://
.
If the pattern matches example.com, which does not have a url scheme
prefix, the supplied scheme will be prepended to create
http://example.com
when the clickable url link is created.
Constants
public static final int ALL
Bit mask indicating that all available patterns should be matched in methods that take an options maskConstant Value: 15 (0x0000000f)
public static final int EMAIL_ADDRESSES
Bit field indicating that email addresses should be matched in methods that take an options maskConstant Value: 2 (0x00000002)
public static final int MAP_ADDRESSES
Bit field indicating that street addresses should be matched in methods that take an options maskConstant Value: 8 (0x00000008)
public static final int PHONE_NUMBERS
Bit field indicating that phone numbers should be matched in methods that take an options maskConstant Value: 4 (0x00000004)
public static final int WEB_URLS
Bit field indicating that web URLs should be matched in methods that take an options maskConstant Value: 1 (0x00000001)
Fields
public static final Linkify.MatchFilter sPhoneNumberMatchFilter
Filters out URL matches that don't have enough digits to be a phone number.public static final Linkify.TransformFilter sPhoneNumberTransformFilter
Transforms matched phone number text into something suitable to be used in a tel: URL. It does this by removing everything but the digits and plus signs. For instance: '+1 (919) 555-1212'becomes '+19195551212'
public static final Linkify.MatchFilter sUrlMatchFilter
Filters out web URL matches that occur after an at-sign (@). This is to prevent turning the domain name in an email address into a web link.Public Constructors
public Linkify ()
Public Methods
public static final boolean addLinks (TextView text, int mask)
Scans the text of the provided TextView and turns all occurrences of the link types indicated in the mask into clickable links. If matches are found the movement method for the TextView is set to LinkMovementMethod.public static final void addLinks (TextView text, Pattern p, String scheme, Linkify.MatchFilter matchFilter, Linkify.TransformFilter transformFilter)
Applies a regex to the text of a TextView turning the matches into links. If links are found then UrlSpans are applied to the link text match areas, and the movement method for the text is changed to LinkMovementMethod.Parameters
text | TextView whose text is to be marked-up with links |
---|---|
p | Regex pattern to be used for finding links |
scheme | Url scheme string (eg http:// to
be prepended to the url of links that do not have a scheme
specified in the link text |
matchFilter | The filter that is used to allow the client code additional control over which pattern matches are to be converted into links. |
public static final boolean addLinks (Spannable text, int mask)
Scans the text of the provided Spannable and turns all occurrences of the link types indicated in the mask into clickable links. 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.public static final boolean addLinks (Spannable s, Pattern p, String scheme, Linkify.MatchFilter matchFilter, Linkify.TransformFilter transformFilter)
Applies a regex to a Spannable turning the matches into links.Parameters
s | Spannable whose text is to be marked-up with links |
---|---|
p | Regex pattern to be used for finding links |
scheme | Url scheme string (eg http:// to
be prepended to the url of links that do not have a scheme
specified in the link text |
matchFilter | The filter that is used to allow the client code additional control over which pattern matches are to be converted into links. |
public static final boolean addLinks (Spannable text, Pattern pattern, String scheme)
Applies a regex to a Spannable turning the matches into links.Parameters
text | Spannable whose text is to be marked-up with links |
---|---|
pattern | Regex pattern to be used for finding links |
scheme | Url scheme string (eg http:// to
be prepended to the url of links that do not have a scheme
specified in the link text
|
public static final void addLinks (TextView text, Pattern pattern, String scheme)
Applies a regex to the text of a TextView turning the matches into links. If links are found then UrlSpans are applied to the link text match areas, and the movement method for the text is changed to LinkMovementMethod.Parameters
text | TextView whose text is to be marked-up with links |
---|---|
pattern | Regex pattern to be used for finding links |
scheme | Url scheme string (eg http:// to
be prepended to the url of links that do not have a scheme
specified in the link text.
|
MatchFilter
MatchFilter
enables client code to have more control over what is allowed to
match and become a link, and what is not. For example: when matching
web urls you would like things like http://www.example.com to match,
as well as just example.com itelf. However, you would not want to
match against the domain in support@example.com. So, when matching
against a web url pattern you might also include a MatchFilter that
disallows the match if it is immediately preceded by an at-sign (@).
Regular
expressions are a very powerful way to match text patterns, but
sometimes a bit more flexibility is needed. The MatchFilter
class provides this capability by giving user code a chance to
evaluate the link worthiness of some matched text.
import java.util.regex.Pattern;
import android.text.util.Linkify;
import android.text.util.Linkify.MatchFilter;
// A match filter that only accepts odd numbers.
MatchFilter oddFilter = new MatchFilter() {
public final boolean acceptMatch(CharSequence s, int start, int end) {
int n = Character.digit(s.charAt(end-1), 10);
return (n & 1) == 1;
}
};
// Match all digits in the pattern but restrict links to only odd
// numbers using the filter.
Pattern pattern = Pattern.compile("[0-9]+");
Linkify.addLinks(text, pattern, "http://...", oddFilter, null);
public abstract boolean acceptMatch (CharSequence s, int start, int end)
Examines the character span matched by the pattern and determines if the match should be turned into an actionable link.Parameters
s | The body of text against which the pattern was matched |
---|---|
start | The index of the first character in s that was matched by the pattern - inclusive |
end | The index of the last character in s that was matched - exclusive |
Returns
- Whether this match should be turned into a link
TransformFilter
TransformFilter
enables client code to have more control over how matched patterns
are represented as URLs. For example: when converting a phone number
such as (919) 555-1212 into a tel: URL the parentheses, white space,
and hyphen need to be removed to produce tel:9195551212.
Up until this
point, the final link was always being generated based on the exact
matched text. There are many cases where that is not desirable,
however. For example, it's common to mention a username using the
@username
syntax, but the resulting link
should only include the username
portion
of the text. The TransformFilter
class provides a solution.mport java.util.regex.Pattern;
import android.text.util.Linkify;
import android.text.util.Linkify.TransformFilter;
// A transform filter that simply returns just the text captured by the
// first regular expression group.
TransformFilter mentionFilter = new TransformFilter() {
public final String transformUrl(final Matcher match, String url) {
return match.group(1);
}
};
// Match @mentions and capture just the username portion of the text.
Pattern pattern = Pattern.compile("@([A-Za-z0-9_-]+)");
String scheme = "http://twitter.com/";
Linkify.addLinks(text, pattern, scheme, null, mentionFilter);
This approach uses the regular expression's capture
syntax to extract just the username portion of the pattern as a
uniquely addressable match group. Alternatively, the transform filter
could just return all of the matched text after the first character
(
Of course, transform filters can be combined with match filters
for ultimate flexibility. The Android SDK uses this approach to
detect wide ranges of phone number formats (many of which include
various parentheses and dashes) while always generating a simplified
link containing only digits.@
), but the above approach is nice
because it keeps all of the pattern's details within the regular
expression.public abstract String transformUrl (Matcher match, String url)
Examines the matched text and either passes it through or uses the data in the Matcher state to produce a replacement.Parameters
match | The regex matcher state that found this URL text |
---|---|
url | The text that was matched |
Returns
- The transformed form of the URL
Creating Links using Linkify
Linkify
is a class that lets you create links from a TextView or a
Spannable. You can create links not just to web pages, but also to locations on the map, emails and even phone numbers. |
Web address:
TextView myWebSite = new
TextView(this);
myWebSite
.setText("http://http://www.dzone.com/");
Linkify.addLinks(myWebSite ,
Linkify.WEB_URLS);
Phone number:
TextView myPhone = (TextView)
findViewById(R.id.my_web_site); |
myPhone .setText(“5552323233”); |
Linkify.addLinks(myPhone ,
Linkify.PHONE_NUMBERS); |
Map address:
TextView myLocation = new
TextView(this); |
myLocation.setText("436 Mayfield
Ave, Stanford, CA"); |
Linkify.addLinks(myLocation ,
Linkify.MAP_ADDRESSES); |
mainLayout.addView(myLocation); |
Email address:
TextView myEmail= (TextView)
findViewById(R.id.my_web_site); |
myEmail.setText(“aviyehuda@gmail.com”); |
Linkify.addLinks(myEmail ,
Linkify.EMAIL_ADDRESSES); |
Auto detect:
Use Linkify.ALL to automatically detect the link type.
Linkify.addLinks(myTextView ,
Linkify.ALL); |
More than one option:
You can choose more than a single option for the link type.
Linkify.addLinks(myTextView,
Linkify.PHONE_NUMBERS | Linkify.WEB_URLS); |
Using pattern:
You can use a regular expression for detecting text parts and transform only them to links instead of the whole text.
TextView myCustomLink = new
TextView(this); |
Pattern pattern =
Pattern.compile("[a-zA-Z]+&"); |
myCustomLink.setText("press
Linkify& or on Android& to search it on google"); |
Linkify.addLinks(myCustomLink,pattern,
"http://www.google.ie/search?q="); |
mainLayout.addView(myCustomLink); |
MatchFilter:
MatchFilter is used for more complicated filters.
MatchFilter myMatchFilter = new
MatchFilter() { |
@Override |
public
boolean acceptMatch(CharSequence
cs, int start, int end)
{ |
return
start > 48; |
} |
}; |
TextView myCustomLink2 = new
TextView(this); |
Pattern pattern2 =
Pattern.compile("[a-zA-Z]+"); |
myCustomLink2.setText("press one of
these words to search it on google: Android Linkify dzone"); |
Linkify.addLinks(myCustomLink2,pattern2,
"http://www.google.ie/search?q=", myMatchFilter, null); |
mainLayout.addView(myCustomLink2); |
TransformFilter:
So fat the text we have filtered stayed the same. But sometimes you need the text to be different than the text which is appended to the link.
TransformFilter
myTransformFilter = new TransformFilter()
{ |
@Override |
public
String transformUrl(Matcher match, String
url) { |
return
url.substring(1); //remove the $ sign |
} |
}; |
TextView myCustomLink3 = new
TextView(this); |
Pattern pattern3 =
Pattern.compile("\\$[a-zA-Z]+"); |
myCustomLink3.setText("press
$Linkify or on $Android to search it on google"); |
Linkify.addLinks(myCustomLink3,pattern3,
"http://www.google.ie/search?q=", null,
myTransformFilter); |
mainLayout.addView(myCustomLink3); |
Linkify your Text!
For example, in our case we want to look for a regular expression match for a WikiWord (that is, a word with camel case » and no spaces). Linkify can then turn this into a Content URI — something like
content://com.google.android.wikinotes.db.wikinotes/wikinotes/WikiWord
,
which can then be used to locate the correct wiki page from a
ContentProvider
.As a bonus, the Linkify class also defines several default matches, in particular it is able to turn web URLs, email addresses and telephone numbers into active links which fire Android intents automatically.
Linkify can be passed any TextView in your application, and will take care of creating the links and enabling their "clickability" for you.
Default Linkify: Using the set of default active link options is very straightforward. Simply pass it a handle to a TextView with content in it, and the
Linkify.ALL
flag:TextView noteView = (TextView) findViewById(R.id.noteview); noteView.setText(someContent); Linkify.addLinks(noteView, Linkify.ALL);and that's it. The
Linkify.ALL
flag
applies all of the predefined link actions, and the TextView will be
immediately updated with a set of active links which, if you select
them, fire default intents for the actions (e.g. a web URL will
start the browser with that URL, a telephone number will bring up
the phone dialer with that number ready to call, etc.).Custom Linkify: So what about our WikiWord? There is no pre-defined action for that, so it needs to be defined and associated with a scheme.
The first task is to define a regular expression that matches the kind of WikiWords we want to find. The regex in this case is:
\b[A-Z]+[a-z0-9]+[A-Z][A-Za-z0-9]+\bObvious, no? Well actually this is equivalent to the following description: "Starting with a word boundary (the \b) find at least one upper case letter, followed by at least one lower case letter or a numeric digit, followed by another upper case letter, and then any mix of upper case, lower case or numeric until the next word boundary (the final \b)". Regular expressions are not very pretty, but they are an extremely concise and accurate way of specifying a search pattern.
We also need to tell Linkify what to do with a match to the WikiWord. Linkify will automatically append whatever is matched to a scheme that is supplied to it, so for the sake of argument let's assume we have a
ContentProvider
that matches the following content URI:content://com.google.android.wikinotes.db.wikinotes/wikinotes/WikiWordThe WikiWord part will be appended by Linkify when it finds a match, so we just need the part before that as our scheme.
Now that we have these two things, we use Linkify to connect them up:
Pattern wikiWordMatcher = Pattern.compile("\\b[A-Z]+[a-z0-9]+[A-Z][A-Za-z0-9]+\\b"); String wikiViewURL = "content://com.google.android.wikinotes.db.wikinotes/wikinotes/"; Linkify.addLinks(noteView, wikiWordMatcher, wikiViewURL);Note that the \b's had to be escaped with double backslashes for the Java Pattern.compile line.
Linkify can be used multiple times on the same view to add more links, so using this after the Default Linkify call means that the existing active links will be maintained and the new WikiWords will be added. You could define more Linkify actions and keep applying them to the same TextView if you wanted to.
Now, if we have a WikiWord in the TextView, let's say
MyToDoList
,
Linkify will turn it into an active link with the content URI:content://com.google.android.wikinotes.db.wikinotes/wikinotes/MyToDoListand if you click on it, Android will fire the default intent for that content URI.
For this to all work, you will need a ContentProvider that understands that Content URI, and you will need a default activity capable of doing something with the resulting data. I plan to cover these in future blog entries (and soon). In fact, the whole Wiki Note Pad application is currently undergoing some clean up and review, and will then hopefully be released as a sample application.
Custom Link Patterns
Detecting additional types of link patterns is easy, too. TheaddLinks(TextView
text, Pattern pattern, String scheme)
function detects
links based on a regular expression pattern.The text is scanned for pattern matches. Matches are converted to links that are generated by appending the matched text to the provided URL scheme base.
import java.util.regex.Pattern;
import android.text.util.Linkify;
// Detect US postal ZIP codes and link to a lookup service
Pattern pattern = Pattern.compile("\\d{5}([\\-]\\d{4})?");
String scheme = "http://zipinfo.com/cgi-local/zipsrch.exe?zip=";
Linkify.addLinks(text, pattern, scheme);
Default Link Patterns
Enabling support for one of Android's default link patterns is very easy. Simply use theaddLinks(TextView
text, int mask)
function and specify a mask that
describes the desired link types.
import android.text.util.Linkify;
// Recognize phone numbers and web URLs
Linkify.addLinks(text, Linkify.PHONE_NUMBERS | Linkify.WEB_URLS);
// Recognize all of the default link text patterns
Linkify.addLinks(text, Linkify.ALL);
// Disable all default link detection
Linkify.addLinks(text, 0);
Example :
linkifySample
package com.ipsr;
import com.ipsr.R.layout;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.text.util.Linkify;
import android.widget.TextView;
public class LinkifySampleActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tv=(TextView)findViewById(R.id.textView1);
tv.setTextColor(Color.WHITE);
String data="This is sample Linkify coding. \n"+"\n"+"URL:http://www.google.com/"+" \n"+
"email:abc@gmail.com\n"+"Phone: (82)-10-9887-6231 \n" +
"Address: 436 Mayfield Ave, Stanford, CA \n" +
"\n";
if(tv!=null)
{
tv.setText(data);
Linkify.addLinks(tv, Linkify.ALL);
} }
}
main.xml
<?xml
version="1.0"
encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large
Text"
android:textAppearance="?android:attr/textAppearanceLarge"
/>
</LinearLayout>
AndroidManifest.xml
<?xml
version="1.0"
encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ipsr"
android:versionCode="1"
android:versionName="1.0"
>
<uses-sdk
android:minSdkVersion="8"
/>
<uses-permission
android:name="android.permission.INTERNET"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
>
<activity
android:name=".LinkifySampleActivity"
android:label="@string/app_name"
>
<intent-filter>
<action
android:name="android.intent.action.MAIN"
/>
<category
android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
</application>
</manifest>
No comments:
Post a Comment