Applying custom click listeners to different texts in a TextView

Nnabueze Uhiara
3 min readAug 10, 2019

--

There are times when you will have to design the text in the image above. Maybe you want the “here” and “terms and conditions” texts to open different screens when clicked. The first time I had to, I used 4 TextViews: one for “Click”, one for “here”, the third for “ to accept the” and the last for “terms and conditions”. It looked fine and to be honest, I heard no complaints so… 🤷‍♂.

The above-described method has limitations. Say, for instance, your app is translated in 5 or more languages and you want the language equivalents of “here” and “terms and conditions” to behave the same, using the above approach results in messy code and a more stressed you. Simply put, it does not scale well.

You don’t want to be this guy. credit: https://gph.is/1QH7Zt8

A cleaner way: using <annotation>

We are going to use this method to replicate the above design in a sample app that supports French and English.

  1. Wrap phrase(s) to customize with annotation tags i.e <annotation>:
String resource in English
String resource in French

Note: the annotation tag above must have a key-value pair for it to work. In our case, we have the action=”acceptTC” and action=”openTC” key-value pairs. Even if you don’t intend on using it in the code, set a dummy key-value pair.

2. On the Kotlin side, get a list of annotations spans on the text

In the above snippet, note that SpannedString is an immutable copy i.e the content cannot be changed and you cannot add or remove spans. We only need to read from this copy so it’s ideal. The second line gets a list of annotation spans. Also note that Annotation::class.java is of type android.text.Annotation.

3. Create a SpannableString copy of the text and add the needed markups to it.

SpannableString differ from SpannedStrings in that although the contents of both are immutable, markups can be added or removed from the former. Spans are markup objects.

To get our required behaviour, we need an instance of ClickableSpan. ClickableSpan is an abstract class so we need to create a class that extends it and implements the required methods. Ours is the CustomClickSpan class shown below:

Note: if all you need is to handle click events on texts, then you do not need to override updateDrawState.

4. Set SpannbleString to the TextView and wrap up.

Line 2 in the snippet above is needed for the clickListener to be invoked. TextView key events, touches and text-selection are handled by its movementMethod and LinkMovementMethod is appropriate for our use case.

When you run the app without adding code on line3 in the snippet above, you will notice that when you click on the text, a highlightColor shows, if you do not want a visible highlightColor, then line3 is needed.

That’s all! The project repository can be found on GitHub. The screenshots of the resulting English and French versions of the app are shown below:

English version
French version

I hope this helped. Comments are welcome. If you enjoyed this, clap, share and you can also follow me on Twitter. I hope to write more

--

--

Nnabueze Uhiara
Nnabueze Uhiara

Written by Nnabueze Uhiara

Android developer. Life-long learner

Responses (1)