daniyelp
daniyelp

Reputation: 1275

Centering Text in Jetpack Compose

I am trying to center the content inside a Text of Jetpack Compose, but I'm not succeeding. The code seems fine to me (I'm very new to Compose though). The code:

Row(
        modifier = Modifier
            .padding(8.dp)
            .height(30.dp)
            .fillMaxHeight(),
    ) {
        IconButton(..) {..}
        Spacer(modifier = Modifier.width(4.dp))
        Text(
            text = "Some text",
            textAlign = TextAlign.Center,
            modifier = Modifier
                .fillMaxHeight()
                .border(1.dp, Color.Black, RoundedCornerShape(20))
                .width(120.dp)
                .background(color = Color.White, RoundedCornerShape(20))
                .align(Alignment.CenterVertically)
        )
        Spacer(modifier = Modifier.width(4.dp))
        IconButton(..) {..}
    }

This yields the following result: enter image description here

Upvotes: 4

Views: 9730

Answers (3)

Richard Onslow Roper
Richard Onslow Roper

Reputation: 6863

First of all, Compose is different than Android Views in many ways. There is no 'C' in 'View', but 'Composable' STARTS with a 'C'. Ok, so now that the basics are clear, you see the behaviour that you are observing is indeed the expected one. Here's why

Composables, just like views, have bounds (the four corner points separating it from the rest of the environment), which we can modify using Modifiers. Composables including text to be rendered, such as the Text and all the TextFields follow the same basic principle. If I have made my text very large (say a quarter to the maxHeight), then I must have done so because I assume my text value to be placed in is large, or else there is no point of doing that, right? Hence, when you create a Text with dimensions larger than required by the value, it should be treated as a Composable 'ready' to hold the maximum capacity it is composed to.

Ok so if you were to change your text value in such a way so as to center the text, what would you do? You would add Line-Breaks (Press Enter Multiple Times) until the text looks vertically in the middle, but that's just lame. You did not need to specify bounds so large if your value was smaller than would fill the Comp. Let's say a person can modify this value. Every time the value changes, the space from the edges needs to be calculated based on the length of the string + font size + font family + font style. If there is a faster approach, why would a person not take that? You are provided with a golden Modifier called as wrapContentHeight. Now, this will wrap the Composable itself around the text (asynchronously), limiting the amount of space to the required. Ok now that the bounds are set, you can position the Composable literally anywhere you wish to on the screen by specifying the co-ordinates. For the desired behaviour, there's the handy verticalAlignemnt parameter provided with some Composables, or something to that effect, which will automatically and asynchronously do the job for you.

You may as well ask why the horizontal alignment is provided despite having the same effect, I think it is because of the convention that people had been used to since the early typewriting days. The vertical one might be inefficient from a memory and/or performance perspective.

However, if for some bizarre reason you are sworn not to use external Composables for content Alignment, then I guess it is not such a big deal to implement your own version of the aligner. It is just that vertical space is divided into 'lines' of fixed width, and at any given time, a text value can be displayed only on a specific line. Hence, if the height of the Composable is not perfectly an integral multiple of the line-height, it would be tricky to place the block (actually it would be impossible using the pre-built stuff). In your case for example, the Composable does not seem out two line-heights. Now to center, you would have to place it at 1.5 the line height which is something Text cannot achieve, so the line break implementation would fail here. Also the alignment will not be perfect if the height is an even multiple of the line-height.

It's just messed up.

Upvotes: -3

Phil Dukhov
Phil Dukhov

Reputation: 88377

Your Text takes full height according to your modifier, in this case .align(Alignment.Center) won't help you.

You can place your Text inside a Box and center it there:

Row(
    modifier = Modifier
        .padding(8.dp)
        .height(30.dp)
        .fillMaxHeight()
) {
    IconButton({ }) { Text("hello ") }
    Spacer(modifier = Modifier.width(4.dp))
    Box(
        Modifier
            .fillMaxHeight()
            .border(1.dp, Color.Black, RoundedCornerShape(20))
            .width(120.dp)
            .background(color = Color.White, RoundedCornerShape(20))
    ) {
        Text(
            text = "Some text",
            textAlign = TextAlign.Center,
            modifier = Modifier
                .align(Alignment.Center)
        )
    }

    Spacer(modifier = Modifier.width(4.dp))
    IconButton({ }) { Text("hello ") }
}

You can solve this with adding a padding to your text, but in this case you can't specify Row height explicitly, and need to let it wrap content size:

Row(
    verticalAlignment = Alignment.CenterVertically,
    modifier = Modifier
        .padding(8.dp)
) {
    IconButton({ }) { Text("hello ") }
    Spacer(modifier = Modifier.width(4.dp))
    Text(
        text = "Some text",
        textAlign = TextAlign.Center,
        modifier = Modifier
            .border(1.dp, Color.Black, RoundedCornerShape(20))
            .width(120.dp)
            .background(color = Color.White, RoundedCornerShape(20))
            .padding(vertical = 10.dp)
    )
    Spacer(modifier = Modifier.width(4.dp))
    IconButton({ }) { Text("hello ") }
}

Upvotes: 6

Raw Hasan
Raw Hasan

Reputation: 1396

Putting it on a column and centering both ways can also work:

Column(
    modifier = Modifier
        .fillMaxHeight()
        .border(1.dp, Color.Black, RoundedCornerShape(20))
        .width(120.dp)
        .background(color = Color.White, RoundedCornerShape(20)),
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally
) {
    Text(text = "Some text")
}

enter image description here

Upvotes: 2

Related Questions