Reputation: 1275
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:
Upvotes: 4
Views: 9730
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 TextField
s 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
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
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")
}
Upvotes: 2