Drawing and painting in Jetpack Compose #2: About text
Tags: android, kotlin, ux, jetpackcompose
Published: 2021-01-07 16:05:12

Welcome to part 2 of *Drawing and painting in Jetpack Compose*. Today I will be taking a look at text. Given how easy it is to draw dots, lines, arcs and curves, printing some text should be piece of cake, right? Something like

```kotlin
@Composable
fun TextDemo() {
  Canvas(modifier = Modifier.fillMaxWidth().preferredHeight(128.dp),
    onDraw = {
      drawText(Color.Red, center, "Hello Compose")
    })
}
```

Sadly, though, there is no `drawText()`.

That's too bad.

But wait, Android's native canvas class (`android.graphics.Canvas`) does have several `drawText()` versions, one of the simplest ones being `drawText(String text, float x, float y, Paint paint)`. Let's see if we can utilize this. 

Please recall that our `onDraw()` lamba acts as an extension function of `androidx.compose.ui.graphics.drawscope.DrawScope`. Hence, this interface and accompanying extension functions define what we can call inside our code. As it turns out there is `drawIntoCanvas()`. This function allows us to draw directly into the underlying `androidx.compose.ui.graphics.Canvas`. If we peek into its source code we find:

![Source code of Canvas.nativeCanvas](https://dev-to-uploads.s3.amazonaws.com/i/kiqd0y2n154k9h2vdbvz.png)

Finally.

So here is how we can draw text onto our canvas:

```kotlin
@Composable
fun TextDemo() {
  Canvas(modifier = Modifier.fillMaxWidth().preferredHeight(128.dp),
    onDraw = {
      val paint = android.graphics.Paint()
      paint.textAlign = Paint.Align.CENTER
      paint.textSize = 64f
      paint.color = 0xffff0000.toInt()
      drawIntoCanvas {
        it.nativeCanvas.drawText("Hello", center.x, center.y, paint)
      }
    })
}
```

Instead of passing a lambda to `drawIntoCanvas()` you could also write `drawContext.canvas.nativeCanvas.drawText()`. We'll see this in the next example. As we are using the native canvas, we need native ways to customize output. For example, to set an individual font, put the *.ttf* file in *res/font*. Please keep in mind that the filename must meet certain rules (lowercase letters, numbers and the underscore only).

![Using a custom font](https://dev-to-uploads.s3.amazonaws.com/i/2flhuinncjytarfa4wcf.png)

```kotlin
@Composable
fun C64TextDemo() {
  Canvas(modifier = Modifier.fillMaxWidth().preferredHeight(128.dp),
    onDraw = {
      drawRect(Color(0xff525ce6))
      val paint = Paint()
      paint.textAlign = Paint.Align.CENTER
      paint.textSize = 64f
      paint.color = 0xffb0b3ff.toInt()
      paint.typeface = customTypeface
      drawContext.canvas.nativeCanvas.drawText(
        "HELLO WORLD!",
        center.x, center.y, paint
      )
    })
}
```

`customTypeface` is declared like this:

```kotlin
private lateinit var customTypeface: android.graphics.Typeface
```

And then initialized as follows:

```kotlin
customTypeface = resources.getFont(R.font.c64_pro_mono_style)
```

Please be careful not to mix platform classes with Compose functions, classes or interfaces. For example there is `androidx.compose.ui.text.font.Typeface`, which of course cannot be used together with `android.graphics.Paint`. To separate the composable and the old platform world, I chose a toplevel variable, but you could also pass it to your composables as needed. The wonderful C64 font can by the way be downloaded at [style64.org](https://style64.org/c64-truetype).

Before I close this post, let's pay some more attention to styling. For example, to unterline your text, just add

```kotlin
paint.flags = Paint.UNDERLINE_TEXT_FLAG
```

`Paint.STRIKE_THRU_TEXT_FLAG`, well, strikes through the text. Please remember that this is not Compose-specific but ordinary Android framework api.

As Jetpack Compose offers the `Text()` composable, when would we use text on canvas? Generally I suggest to use `Text()` whenever possible. If you recall my `sin()` plotter, which has its own cartesian coordinate system, it may make sense, though, to add labels to its axes using the method I have shown you in this post.

What are your thoughts on using `nativeCanvas`? Please share them in the comments.

---

[source](https://github.com/tkuenneth/android-demos/tree/master/compose/DrawingDemo)