---
title: Using Extension Functions and Operator Overloading on SpannableStrings.
teaser: 'Utilizing Extension Functions and Operator Overloading to Smooth Out Android''s
  Rough Edges.

  '
tags: kotlin,android,mobile
author: Alex Sullivan
published_on: 2018-01-04
---

I'm a big fan of Android development - but there's no denying that there are
some rough API's in the Android ecosystem. I spend a non-trivial amount of time
scratching my head and muttering under my breath trying to figure out what
incantation I need to speak before something works the way I expect it to. As a
result, whenever I have the opportunity to write a wrapper around a particularly
nasty Android API I jump at the opportunity. Now that Kotlin is a first class
citizen in the world of Android, we can use [`Extension
Functions`](https://kotlinlang.org/docs/reference/extensions.html) and
[`Operator
Overloading`](https://kotlinlang.org/docs/reference/operator-overloading.html)
to make some really beautiful API's. Let's walk through an example using the
`SpannableString` API.

## The Rough API

Android provides the `SpannableString` API to customize portions of a
string with some type of custom style - for example, we can style our
string with a black background and red foreground color and make it appear
larger  with the following code:

```kotlin
val firstStyleString = SpannableStringBuilder("Check out this big text with a black background and red foreround")
firstStyleString.setSpan(RelativeSizeSpan(3.5f), 0, firstStyleString.length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)
firstStyleString.setSpan(BackgroundColorSpan(Color.BLACK), 0, firstStyleString.length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)
firstStyleString.setSpan(ForegroundColorSpan(Color.RED), 0, firstStyleString.length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)
```

Not too bad. Not great but its manageable. Now let's say we want to
add another string to this one that has a strikethrough style. The code
now looks like this:

```kotlin
val firstStyleString = SpannableStringBuilder("Check out this big text with a black background and red foreround")
firstStyleString.setSpan(RelativeSizeSpan(3.5f), 0, firstStyleString.length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)
firstStyleString.setSpan(BackgroundColorSpan(Color.BLACK), 0, firstStyleString.length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)
firstStyleString.setSpan(ForegroundColorSpan(Color.RED), 0, firstStyleString.length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)

val secondStyleString = SpannableStringBuilder(" And now check out this text with a strikethrough style!")
secondStyleString.setSpan(StrikethroughSpan(), 0, secondStyleString.length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)

val appendedString = SpannableStringBuilder(firstStyleString).append(secondStyleString)
```

Alright, things are starting to get pretty ugly. That's a lot of cryptic
code to get a styled string.

Let's utilize some of Kotlin's many awesome features to clean up this
API.

## Introducing extension functions

First off we're going to utilize `Extension Functions` to make this API
more fluent. If you haven't used Kotlins `Extension Functions` yet
you're in for a treat. They allow you to extend a classes functionality
without inheriting from that class or modifying the core class. You can
add extension methods or properties to any class you want, including
Android framework classes. Pretty sweet.

## Building a nicer API via extension functions

We can add an `Extension Function` to `SpannableStringBuilder` to make the
block above a bit less gross:

```kotlin
fun SpannableStringBuilder.spanText(span: Any): SpannableStringBuilder {
  setSpan(span, 0, length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)
  return this
}
```

This function gives us a nice way to hide the ugly internals of
`SpannableString`. Our block above now looks like this:

```kotlin
val firstStyleString = SpannableStringBuilder("Check out this big text with a black background and red foreground")
        .spanText(RelativeSizeSpan(3.5f))
        .spanText(BackgroundColorSpan(Color.BLACK))
        .spanText(ForegroundColorSpan(Color.RED))

val secondStyleString = SpannableStringBuilder(" And now check out this text with a strikethrough style!")
        .spanText(StrikethroughSpan())

val appendedString = SpannableStringBuilder(firstStyleString).append(secondStyleString)
```

Nice. But we can still do better - really all we want to say is "Here's
a string, it should be this big, have a black background, and a red
foreground". The block above still has a lot of boilerplate involved.

Let's add a few more extension functions to get us to a nice spot:

```kotlin
private fun CharSequence.toSpannable() = SpannableStringBuilder(this)

fun CharSequence.foregroundColor(@ColorInt color: Int): SpannableStringBuilder {
  val span = ForegroundColorSpan(color)
  return toSpannable().spanText(span)
}

fun CharSequence.backgroundColor(@ColorInt color: Int): SpannableStringBuilder {
  val span = BackgroundColorSpan(color)
  return toSpannable().spanText(span)
}

fun CharSequence.relativeSize(size: Float): SpannableStringBuilder {
  val span = RelativeSizeSpan(size)
  return toSpannable().spanText(span)
}

fun CharSequence.supserscript(): SpannableStringBuilder {
  val span = SuperscriptSpan()
  return toSpannable().spanText(span)
}

fun CharSequence.strike(): SpannableStringBuilder {
  val span = StrikethroughSpan()
  return toSpannable().spanText(span)
}
```

The above defines several functions to convert a `CharSequence` to a
`SpannableStringBuilder` and apply a certain style to it. Now our API
looks like this:

```kotlin
val firstStyleString = "Check out this big text with a black background and red foreground"
        .relativeSize(3.5f)
        .backgroundColor(Color.BLACK)
        .foregroundColor(Color.RED)

val secondStyleString = " And now check out this text with a strikethrough style!"
        .strike()

val appendedString = SpannableStringBuilder(firstStyleString).append(secondStyleString)
```

Niiicceee. We've ditched all of that boilerplate and replaced it with a
much more readable code block. But we can still do better.

## Introducing operator overloading

Another nice feature Kotlin provides is `operator overloading`. Kotlin
exposes a series of special symbols such as `+` , `*`, `-`, and `%` that
developers can overload for their own classes. You can also utilize
those operators on existing classes outside of your control via
`Extension Functions`.

## Using operator overloading to make our API even better

One of the sore points of our current `SpannableString` code block is
this line:

```kotlin
val appendedString = SpannableStringBuilder(firstStyleString).append(secondStyleString)
```

It breaks the clean flow we've been building up and exposes the
`SpannableStringBuilder` that we've been working to hide. Luckily we can
utilize the `+` operator to make things clearer:

```kotlin
operator fun SpannableStringBuilder.plus(other: SpannableStringBuilder): SpannableStringBuilder {
  return this.append(other)
}

operator fun SpannableStringBuilder.plus(other: CharSequence): SpannableStringBuilder {
  return this + other.toSpannable()
}
```

now the above line is shortened to the following:

```kotlin
val appendedString = firstStyleString + secondStyleString
```

b-e-a-utiful. Now it's immediately clear what's happening at each stage
of our string-building experience. We can even add another normal string
into the mix easy-peasy:

```kotlin
val firstStyleString = "Check out this big text with a black background and red foreround"
        .relativeSize(3.5f)
        .backgroundColor(Color.BLACK)
        .foregroundColor(Color.RED)

val secondStyleString = " And now check out this text with a strikethrough style!"
        .strike()

val appendedString = firstStyleString + secondStyleString + " And a regular string! "
```

## Extending our API

Another common requirement when using the `SpannableString` API is
apply a style to a single word in a string. We can utilize the `set`
operator in Kotlin to enhance our API and accomplish this task:

```kotlin
operator fun SpannableStringBuilder.set(old: CharSequence, new: SpannableStringBuilder): SpannableStringBuilder {
  val index = indexOf(old.toString())
  return this.replace(index, index + old.length, new, 0, new.length)
}
```

Now we can use indexed accessor properties to replace one of the words
with whatever we want, like this:

```kotlin
appendedString["regular"] = "green".foregroundColor(Color.GREEN)
```

## Final product

Our final code is now much cleaner and much more straightforward to
reason about:

```kotlin
val firstStyleString = "Check out this big text with a black background and red foreround"
        .relativeSize(3.5f)
        .backgroundColor(Color.BLACK)
        .foregroundColor(Color.RED)

val secondStyleString = " And now check out this text with a strikethrough style!"
        .strike()

val appendedString = firstStyleString + secondStyleString + " And a regular string! "
appendedString["regular"] = "GREEN".foregroundColor(Color.GREEN)
```

Another great way to clean up this particular API would be by wrapping the
`StringBuilder` object in a `DSL` - but we'll save that for another blog post.
Its clear that Kotlin can help reshape some of Androids rougher API's, and I
for one am super excited to see what the community will build.
