androidandroid-jetpack-composeandroid-jetpack

How to show vertical text with proper size/layout in jetpack compose


How does one properly rotate text in jetpack compose and get it to do a correct layout? When I use the rotate modifier on a Text object the text is rotated but the size taken up in the layout seems to be using the pre-rotated text width.

Here is a simple example of what I am trying to accomplish - the vertical text should be along the left side in a narrow space:

@Composable
fun MainBox() {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            modifier = Modifier.padding(4.dp).background(Color.Gray),
            text = "This is at the top"
        )

        Row(
            modifier = Modifier.fillMaxWidth().weight(1f),
            verticalAlignment = Alignment.CenterVertically
        ) {

            Text(
                modifier = Modifier.padding(4.dp).rotate(-90f),
                text = "This should be vertical text on the left side"
            )

            Text(
                modifier = Modifier.fillMaxSize().background(Color.Yellow),
                textAlign = TextAlign.Center,
                text = "This is a big yellow box that should take up most of the space"
            )
        }
    }
}

However, what this shows is this.

long vertical text

If I shorten the text in the vertical text it only takes up a narrow space, which looks more like the layout I want.

short vertical text

Is there a way to intercept the layout process or some other setting to use to fix the sizes so that the vertical text takes up only one text row's width of horizontal space, but still adapts to user font size changes (so no fixed sizes)?

Answers to similar questions here and here do not solve this problem or no longer work.


Solution

  • My version. After a few tests it seems to work pretty well

    class ComposeActivity7 : ComponentActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            setContent {
                ComposeTutorialTheme {
    
                    Column(
                        modifier = Modifier.fillMaxSize(),
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                        Text(
                            modifier = Modifier
                                .padding(4.dp)
                                .background(Color.Gray),
                            text = "This is at the top"
                        )
    
                        Row(
                            modifier = Modifier
                                .fillMaxWidth()
                                .weight(1f),
                            verticalAlignment = Alignment.CenterVertically
                        ) {
                            Text(
                                modifier = Modifier
                                    .vertical()
                                    .rotate(-90f)
                                    .background(Color.Gray)
                                    .padding(4.dp),
                                text = "This should be vertical text on the left side"
                            )
                            Text(
                                modifier = Modifier
                                    .fillMaxSize()
                                    .background(Color.Yellow),
                                textAlign = TextAlign.Center,
                                text = "This is a big yellow box that should take up most of the space"
                            )
                        }
                    }
                }
            }
        }
    }
    
    fun Modifier.vertical() =
        layout { measurable, constraints ->
            val placeable = measurable.measure(constraints)
            layout(placeable.height, placeable.width) {
                placeable.place(
                    x = -(placeable.width / 2 - placeable.height / 2),
                    y = -(placeable.height / 2 - placeable.width / 2)
                )
            }
        }
    
    

    Result

    enter image description here