Search code examples
androidandroid-layoutandroid-jetpack-compose

Align Image with Text baseline in a Row


How can I align an Image with a Text's baseline in a Row. Modifier.alignByBaseline() works for the Texts but the Image doesn't participate in the alignment.

@Composable
fun Sample() {
    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.Center,
    ) {
        Text(
            text = "One",
            modifier = Modifier.alignByBaseline(),
            fontSize = 40.sp
        )
        Image(
            modifier = Modifier
                .padding(horizontal = 8.dp)
                .size(24.dp)
                .alignBy(FirstBaseline),
            painter = painterResource(id = R.drawable.ic_launcher_background),
            contentDescription = "",
        )
        Text(
            text = "two",
            modifier = Modifier.alignByBaseline(),
            fontSize = 40.sp
        )
    }
}

enter image description here


Solution

  • alignByBaseline aligns item by it's own baseline, not neighbours ones.

    You can use paddingFromBaseline for Text and same value for image padding with verticalAlignment = Alignment.Bottom.

    And to get actual value of baseline offset to pass it to the padding modifier, you need to wait for TextLayoutResult: it gets called when text layout is calculated depending on text size, font, etc.

    Row(
        horizontalArrangement = Arrangement.Center,
        verticalAlignment = Alignment.Bottom,
        modifier = Modifier.fillMaxWidth()
    ) {
        var maxBaseline by remember { mutableStateOf(0f) }
        fun updateMaxBaseline(textLayoutResult: TextLayoutResult) {
            maxBaseline = max(maxBaseline, textLayoutResult.size.height - textLayoutResult.lastBaseline)
        }
        val topBaselinePadding = with(LocalDensity.current) { maxBaseline.toDp() }
        Text(
            text = "One",
            modifier = Modifier.paddingFromBaseline(bottom = topBaselinePadding),
            fontSize = 20.sp,
            onTextLayout = ::updateMaxBaseline
        )
        Image(
            painter = painterResource(id = R.drawable.ic_launcher_background),
            contentDescription = "",
            modifier = Modifier
                .padding(bottom = topBaselinePadding)
                .size(24.dp)
        )
        Text(
            text = "two",
            modifier = Modifier.paddingFromBaseline(bottom = topBaselinePadding),
            fontSize = 40.sp,
            onTextLayout = ::updateMaxBaseline
        )
    }