How to convert TextStyle from Jetpack Compose to android.graphics.Typeface?

3.5k Views Asked by At

I need to draw text onto Canvas in Compose, for this purpose I need a TextPaint with android.graphics.Typeface.

Is there a way to easily convert Compose TextStyle to a android.graphics.Typeface?

5

There are 5 best solutions below

2
Jaya Surya Thotapalli On BEST ANSWER

You can resolve android.graphics.Typeface object from a androidx.compose.ui.text.TextStyle object using LocalFontFamilyResolver.

val style: TextStyle = MaterialTheme.typography.body1
val resolver: FontFamily.Resolver = LocalFontFamilyResolver.current

val typeface: Typeface = remember(resolver, style) {
    resolver.resolve(
        fontFamily = style.fontFamily,
        fontWeight = style.fontWeight ?: FontWeight.Normal,
        fontStyle = style.fontStyle ?: FontStyle.Normal,
        fontSynthesis = style.fontSynthesis ?: FontSynthesis.All,
    )
}.value as Typeface
1
Ajaz Ahmed On

Currently the only workaround that i found is to provide with resources:

val textTypeface: android.graphics.Typeface? =
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) LocalContext.current.resources.getFont(R.font.quicksand_light) else null

However if android version < android oreo, idk how to provide the font, so i fallback to default fount.

1
RaBaKa 78 On

To draw text to canvas, you can do like this

@Composable
fun DrawText() {
    val paint = Paint().asFrameworkPaint()
    Canvas(modifier = Modifier.fillMaxSize()) {
        paint.apply {
            isAntiAlias = true
            textSize = 24f
            typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD) // your typeface

            //other methods like color, dither, fontMetrics, shadow etc...are also available 

        }

        drawIntoCanvas {
            it.nativeCanvas.drawText("Hello World", size.width/2, size.height/2, paint)
        }
    }
}

I think to convert TextStyle(compose library) to typeface will be a pain since no support from android, If you want to draw text to canvas I think this will be enough

1
OneDev On

try this

    val textPaint = TextPaint()
    val context = LocalContext.current
    Canvas(modifier = Modifier.fillMaxWidth()) {
        textPaint.apply {
            typeface = Typeface.createFromAsset(context.assets, "fonts/yourfont.ttf")
                ...
        }
        drawContext.canvas.nativeCanvas.drawText("test", yourStart, yourEnd, X, Y, textPaint)
    }
0
vpuonti On

I ran into the same issue as you: Wanting to draw text to a Canvas in a TextStyle that is defined in my Compose Theme.

I found out you can use androidx.compose.ui.text.Paragraph.paint(canvas) to draw text to the Canvas.

That in itself has no way to set offsets for the paint job, so you can use drawContext.canvas.nativeCanvas.withTranslation() to move the drawing to a specified offset.

val paragraph = Paragraph(
  text = "Hello",
  style = MaterialTheme.typography.titleLarge,
  constraints = Constraints(),
  density = LocalDensity.current,
  fontFamilyResolver = LocalFontFamilyResolver.current,
)
val colorOnSurface = MaterialTheme.colorScheme.onSurface

Canvas(
  modifier = Modifier.fillMaxSize()
) {
  //
  drawContext.canvas.nativeCanvas.withTranslation(
    100f,
    100f
  ) {
      paragraph.paint(
        canvas = drawContext.canvas,
        color = colorOnSurface,
      )
  }
}

This seems quite sketchy, but it's the best I've got ¯_(ツ)_/¯.