Text composable using Annotated String unexpectedly takes up the same colour as a Button() placed within the same row

3.8k Views Asked by At

I built a composable which is basically a Row containing an address as Text and a Button alongside it. The address contains a label within it (e.g. 'Bill To: ') and to format it slightly differently I am using the buildAnnotatedString function.

This is pretty straightforward, but I am noticing an issue when during the first run, the address Text takes the colour assigned to the Button composable. I have verified this by changing the Button colour, and each time the result is the same on the first run. On subsequent runs, the composable behaves as expected, i.e. the Text is rendered as black as specified in the text-style. Can anyone please explain why this happens or let me know if this should be logged as an issue with the Jetpack Compose team?

Screenshot from the emulator of the first run (reproduced on physical Redmi devices as well): screenshot of the issue

Screenshot representing subsequent runs and the expected behaviour: screenshot of the expected behaviour

My Composable function:

@Composable
fun CheckoutAddress(
    modifier: Modifier = Modifier,
    addressLabel: String,
    address: String?,
    onChangeClick: () -> Unit
) {
    val separator = ": "
    val addressText = buildAnnotatedString {
        appendMedium(addressLabel)
        appendMedium(separator)
        addStyle(
            SpanStyle(
                fontSize = MaterialTheme.typography.body1.fontSize
            ),
            start = 0,
            end = "$addressLabel$separator".length - 1
        )
        if(address.isNullOrBlank()) {
            appendColored(stringResource(id = R.string.label_not_set), color = MaterialTheme.colors.error)
        } else {
            append(address)
        }
    }
    Row(
        modifier = modifier,
        verticalAlignment = Alignment.CenterVertically
    ) {

        Text(
            modifier = Modifier
                .weight(1f)
                .padding(end = CONTENT_TO_BUTTON_PADDING.dp),
            text = addressText,
            style = MaterialTheme.typography.body2,
            maxLines = 4,
            overflow = TextOverflow.Ellipsis
        )

        ChangeButton(
            onClick = onChangeClick
        )
    }
}

The ChangeButton composable (The R.colors.default_blue colour specified within this composable's scope is taken up by the annotated string Text, have changed its value and verified) :

@Composable
fun ChangeButton(
    modifier: Modifier = Modifier,
    onClick: () -> Unit
) {
    TextButton(
        modifier = modifier,
        onClick = onClick,
        colors = ButtonDefaults.textButtonColors(contentColor = colorResource(id = R.color.defaultBlue))
    ) {
        Text(
            text = stringResource(id = R.string.label_change_button).uppercase()
        )
    }
}

The Annotated String helper methods used above:

fun AnnotatedString.Builder.appendMedium(text: String) {
    append(AnnotatedString(text, SpanStyle(fontWeight = FontWeight.Medium)))
}

fun AnnotatedString.Builder.appendColored(text: String, color: androidx.compose.ui.graphics.Color) {
    append(AnnotatedString(
        text,
        SpanStyle(color = color)
    ))
}
0

There are 0 best solutions below