Android bits and pieces: hyperlinks

February 22nd, 2011

This tweet from Kevin Barnes crossed my stream last Saturday:

He posted the solution overview shortly thereafter, but i thought i’d summarize the different ways to display and handle hyperlinks in Android.

The core TextView component provides a nice range of features that make it a prime candidate for displaying hyperlinks. If your text and hyperlink address are static, the simplest way would be to define a string in your resource file. The string can contain the any number of embedded links, for example:

<string name="help_center">Visit the 
    &lt;a href=\&quot;http://my.company.com/help\&quot;\&gt;Help 
    center&lt;/a&gt;</string>

Now, you can either call setText(R.string.help_center) API or simply point to that string from your layout XML:

<TextView android:text="@string/help_center" ... />

At runtime, the framework will find the matching string (which can be in a localized folder), convert it to a properly formatted representation and register a click listener to launch the browser to view the associated link. There are two more things that you should do. First, use the android:textColorLink attribute to control the color of the link elements. Second, locate your TextView when the activity is created and call setMovementMethod(LinkMovementMethod.getInstance()) on it. This will allow users to navigate your links with a navigation ball, d-pad or any other focus traversal aid.

Let’s take this a step further – what if the link itself or the surrounding text are dynamic? Here, you can use the TextView.setText(CharSequence) API where the parameter is constructed dynamically based on your specific application logic. However, there is an additional step to do before calling that API. Once you have constructed the string – with one or more hyperlink segments in it – call Html.fromHtml(String) method. This will properly delineate the link segments and register the click listeners.

Note that up until now i haven’t addressed the original question posted by Kevin. Opening the hyperlink address in the browser might not be the optimal solution for all cases. You might not want to transfer the user to a full-screen browser, preferring to display the content in a floating dialog. Or perhaps you need to put additional controls around the hyperlink content. Or perhaps you don’t have any hyperlink content per-se, but rather need to run some custom logic on activating that segment (be careful though not to diverge too far away from the well-known pattern of hyperlink handling).

If you want to attach a custom listener to be invoked when the user activates the specific text segment, you will need to do the following:

  • Create an instance of SpannableStringBuilder.
  • Use the different append and insert methods to create the text content. Note that here you’re not going to create any explicit a href spans.
  • For every “hyperlink” span, call the setSpan() API as shown below.
  • Call TextView.setText(CharSequence) API, passing your instance of the SpannableStringBuilder to it.
  • As before, call TextView.setMovementMethod(LinkMovementMethod.getInstance()) to enable proper focus traversal of your custom spans.

Here is an example of specifying and configuring a custom span:

SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
stringBuilder.append(leading);
stringBuilder.append(middle);
stringBuilder.append(trailing);
stringBuilder.setSpan(
    new ClickableSpan() {
        @Override
        public void onClick(View widget) {
            // handle span activation (show dialog, ...)
        }
    },
    leading.length(), leading.length() + middle.length(),
    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
myTextView.setText(stringBuilder);