My Problem:
I want to place my Text() content to center of the page in Scaffold.
I tried "textAlign = TextAlign.Center" - It align the text in horizontal area alone. Not align the text in vertical area.
My code:
#Composable
fun ScaffoldWithTopBar() {
Scaffold(
topBar = {
TopAppBar(
title = {
Text(text = "Top App Bar")
},
navigationIcon = {
IconButton(onClick = {}) {
Icon(Icons.Filled.ArrowBack, "backIcon")
}
},
backgroundColor = MaterialTheme.colors.primary,
contentColor = Color.White,
elevation = 10.dp
)
}, content = {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(0xff8d6e63)),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
}
Text(
text = "Content of the page",
fontSize = 30.sp,
color = Color.White
)
})
}
Note: I haven't place this text into Column. I used directly.
My output:
Question:
How to place the text into the center of the parent?
Assign the fillMaxSize() to the parent container, not to the Text:
Box(Modifier.fillMaxSize(),
contentAlignment = Center
) {
Text(
text = "Content of the page",
fontSize = 30.sp,
modifier = Modifier
.background(Color(0xffb3e5fc)),
)
}
or:
Column(Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Content of the page",
fontSize = 30.sp,
modifier = Modifier
.background(Color(0xffb3e5fc)),
)
}
You need to place it inside a Box, and specify contentAlignment
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxSize()
) {
Text(
text = "Content of the page",
fontSize = 30.sp,
modifier = Modifier
.background(Color(0xffb3e5fc)),
)
}
If you wanna align different Box children differently, you can use .align modifier for each item. Note that it's only available inside BoxScope, also there's same modifier for Column and Row.
Box(
modifier = Modifier
.fillMaxSize()
) {
Text(
text = "Content of the page", textAlign = TextAlign.Center,
fontSize = 30.sp,
modifier = Modifier
.background(Color(0xffb3e5fc))
.align(Alignment.Center)
)
}
Box(
modifier = Modifier
.fillMaxSize()
) {
Text(
text = stringResource(id = R.string.social_list_empty),
style = TextStyle(fontSize = 16.sp),
modifier = Modifier
.padding(8.dp)
.align(Alignment.Center),
textAlign = TextAlign.Center
)
}
Reference : For more sample codes of Jetpack Compose, check this
The content in Scaffold is a Composable function in which there is no position info for items by default. In your case, the default position of Text is the top left of its parent view. The solutions putting the Text inside the Box/Colum works, as now Text is put in the center of the Box or Colum, which takes the whole screen. We see Text is in the center of the screen, while the truth is Text is in the center of Box or Colum.
Related
I am trying to overlap two different compose elements. I want to show a toast kind of message at the top whenever there is an error message. I don't want to use a third party lib for such an easy use case. I plan to use the toast in every other composable screen for displaying error message. Below is the layout which i want to achieve
So I want to achieve the toast message saying "Invalid PIN, please try again".
#Composable
fun MyToast(title: String) {
Card(
modifier = Modifier
.absoluteOffset(x = 0.dp, y = 40.dp)
.background(
color = MaterialTheme.colors.primaryVariant,
shape = RoundedCornerShape(10.dp)
), elevation = 20.dp
) {
Row(
modifier = Modifier
.background(color = MaterialTheme.colors.primaryVariant)
.padding(12.dp),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = R.drawable.error_circle),
contentDescription = title
)
Text(
text = title,
fontFamily = FontFamily(Font(R.font.inter_medium)),
fontSize = 12.sp,
color = MaterialTheme.colors.primary,
modifier = Modifier.padding(horizontal = 10.dp)
)
}
}
}
and my screen composable is as follows
#Composable
fun Registration(navController: NavController, registrationViewModel: RegistrationViewModel) {
Scaffold() {
Box(){
MyToast(
title = "Invalid pin, please try again"
)
Column() {
//my other screen components
}
}
}
I will add the AnimatedVisibility modifier later to MyToast composable. First I need to overlap MyToast over all the other elements and somehow MyToast is just not visible
If you want the child of a Box to overlay/overlap its siblings behind, you should put it at the last part in the code
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier.background(Color.Red).size(150.dp)
)
// your Toast
Box(
modifier = Modifier.background(Color.Green).size(80.dp)
)
}
So if I put the green box before the bigger red box like this
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
// your Toast
Box(
modifier = Modifier.background(Color.Green).size(80.dp)
)
Box(
modifier = Modifier.background(Color.Red).size(150.dp)
)
}
the green box will hide behind the red one
You have to solutions, you can either put the Toast in the bottom of your code because order matters in compose:
#Composable
fun Registration(navController: NavController, registrationViewModel: RegistrationViewModel) {
Scaffold() {
Box() {
Column() {
//my other screen components
}
MyToast(
title = "Invalid pin, please try again"
)
}
}
}
Or you can keep it as it is, but add zIndex to the Toast:
#Composable
fun MyToast(title: String) {
Card(
modifier = Modifier
.absoluteOffset(x = 0.dp, y = 40.dp)
.zIndex(10f) // add z index here
.background(
color = MaterialTheme.colors.primaryVariant,
shape = RoundedCornerShape(10.dp)
), elevation = 20.dp
) {
Row(
modifier = Modifier
.background(color = MaterialTheme.colors.primaryVariant)
.padding(12.dp),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = R.drawable.error_circle),
contentDescription = title
)
Text(
text = title,
fontFamily = FontFamily(Font(R.font.inter_medium)),
fontSize = 12.sp,
color = MaterialTheme.colors.primary,
modifier = Modifier.padding(horizontal = 10.dp)
)
}
}
}
Note: elevation in Card composable is not the same as elevation in XML so it's not going to make the composable in the top, it will just add a shadow but if you want to give the composable a higher z order use Modifier.zIndex(10f)
I'am new to jetpack compose and i really liked it. But ran into a problem : I want to create a card and inside of it, i would like to display a list of item with divider between them. I was almost able to achieved it here is my code :
Box(modifier = Modifier.background(Color(0xFFf4f4f4))
.fillMaxSize()
.padding(top = 20.dp)) {
Card(
modifier = Modifier
.fillMaxWidth(),
shape = RoundedCornerShape(20.dp),
elevation = 5.dp
) {
val colorNamesList = listOf("Red", "Green", "Blue", "Indigo")
LazyColumn() {
itemsIndexed(
colorNamesList,
) { index, item ->
Column(
modifier = Modifier
.background(
color = Color(0xFFf2f2f2),
)
.clickable {
println(item)
},
horizontalAlignment = Alignment.CenterHorizontally,//those 2 does nothing
verticalArrangement = Arrangement.Center //when i change it nothing change
) {
println(item + index)
Text(
text = "Item at $item",
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
//textAlign = TextAlign.Center, without it image 1, with it image 2
color = Color.Black,
)
if (index < colorNamesList.lastIndex) {
Divider(
color = Color.Black.copy(alpha = 0.2f),
modifier = Modifier
.padding(horizontal = 80.dp),
)
}
}
}
}
}
}
It's almost good but i didn't managed to align the text inside it, i searched some answer but Alignment and Arrangement doesn't change anything in my situation.
I was able to align horizontally by adding textAlign = TextAlign.Center as i commented in my code but, i couldn't align vertically, the text stay on the top of his cell :
What i want to do is text center in every cell of the column. Thanks for the help.
You can achieve this by adding similar xml attribute like "wrap_content" as height in compose too.
Add "wrapContentHeight()" to modifier and you will get it to align to centre of the page.
Text(
text = "Item at $item",
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.wrapContentHeight(),
textAlign = TextAlign.Center
color = Color.Black,
)
How can we achieve this in jetpack compose
I'm doing something like this
Button(
elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 8.dp,
disabledElevation = 0.dp
),
onClick = { onClick },
shape = RoundedCornerShape(28.dp),
modifier = modifier
.fillMaxWidth()
.shadow(0.dp),
contentPadding = PaddingValues(15.dp),
colors = ButtonDefaults.buttonColors(backgroundColor = Color.White),
border = BorderStroke(1.dp, Color.Grey)
) {
Box(modifier = modifier.fillMaxWidth(),
contentAlignment = Alignment.Center) {
Icon(
imageVector = imageVector,
modifier = Modifier
.size(18.dp),
contentDescription = "drawable icons",
tint = Color.Unspecified
)
Spacer(modifier = Modifier.width(10.dp))
Text(
text = buttonText,
color = Color.Black,
textAlign = TextAlign.Center
)
}
}
So as you can see the Google logo is just left of the text I need it at the start of the box so how can I do this.
You can use align(Alignment.CenterStart) on the Icon's Modifier parameter to center the icon around the start of the Box Composable. This alignment will have priority over the Box's alignment parameter.
You can also delete the Spacer composable because the Box layout children are stacked one on top of the other in the composition order. So the Spacer composable is basically laying below the Text composable in the center.
If you want some space between the Icon and the Text, you could use some padding around the Icon instead.
Try this (It worked for me) :
Box(modifier = modifier.fillMaxWidth(),
contentAlignment = Alignment.Center) {
Icon(
imageVector = imageVector,
modifier = Modifier
.size(18.dp)
.align(Alignment.CenterStart),
contentDescription = "drawable icons",
tint = Color.Unspecified
)
Text(
text = buttonText,
color = Color.Black,
textAlign = TextAlign.Center
)
}
#Composable
fun GoogleButton(
modifier: Modifier = Modifier,
imageVector: ImageVector,
buttonText: String,
onClick: (isEnabled: Boolean) -> Unit = {},
enable: Boolean = true,
backgroundColor: Color,
fontColor: Color,
) {
Button(
onClick = { onClick(enable) },
modifier = modifier
.fillMaxWidth()
.shadow(0.dp)
.noInteractionClickable(enabled = false) { onClick(enable) },
elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 0.dp,
hoveredElevation = 0.dp,
focusedElevation = 0.dp
),
shape = RoundedCornerShape(28.dp),
contentPadding = PaddingValues(15.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = backgroundColor,
contentColor = fontColor
),
border = BorderStroke(1.dp, MaterialTheme.colors.getButtonBorderStroke)
) {
Box(
modifier = Modifier
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
Row(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.CenterStart)
) {
Spacer(modifier = Modifier.width(4.dp))
Icon(
imageVector = imageVector,
modifier = Modifier
.size(18.dp),
contentDescription = "drawable_icons",
tint = Color.Unspecified
)
}
Text(
modifier = Modifier.align(Alignment.Center),
text = buttonText,
color = MaterialTheme.colors.loginButtonTextColor,
textAlign = TextAlign.Center,
fontSize = 16.sp,
fontFamily = FontFamily(
Font(
R.font.roboto_medium
)
)
)
}
}
}
As suggested in other answers you can wrap the content with a Box.
As alternative you can simply use the RowScope of the Button without any container.
Just apply a weight(1f) modifier to the Text and an offset(x=- iconWidth/2).
Something like:
Button(
//....
) {
Icon(
imageVector = imageVector,
modifier = Modifier.size(iconWidth),
contentDescription = "drawable icons",
tint = Color.Unspecified
)
Text(
text = "Button",
color = Color.Black,
textAlign = TextAlign.Center,
modifier = Modifier
.weight(1f)
.offset(x= -iconWidth/2) //default icon width = 24.dp
)
}
If you want to use a Box, remove the contentAlignment = Alignment.Center in the Box and use:
Box(modifier = Modifier.fillMaxWidth()) {
Icon( /* ..... */ )
Text(
modifier = Modifier.fillMaxWidth(),
text = "buttonText",
textAlign = TextAlign.Center
)
}
Box doesn't provide bounds, so for longer texts, it causes overlapping. Row works better for me. Also, you can use Spacer here which is not possible for Box. In my case, I have used spacedBy as a replacement for Spacer:
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter,
contentDescription = null
)
Box(
modifier = Modifier.weight(1F),
contentAlignment = Alignment.Center
) {
Text(buttonText)
}
}
Box(contentAlignment = Center){
Icon(Modifier.align(CenterStart))
Text()
}
I have this composable :
#Composable
fun MyApp() {
var isSelected by remember { mutableStateOf(false) }
val backgroundColor by animateColorAsState(if (isSelected) Color.Red else Color.Transparent)
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Hello",
modifier = Modifier.background(color = backgroundColor)
.clickable(onClick = { isSelected = !isSelected })
.width(100.dp)
.height(40.dp),
textAlign = TextAlign.Center,
)
}
}
I expect TextAlign.Center centerlize Text of TextView, but it will be just centerlize horizontally. How can I make it center vertically as well?
TextAlign.Center can only center your content horizontally.
To center it vertically you need to place it inside a container, like Box, and apply content alignment and your size modifiers to this container:
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.width(100.dp)
.height(40.dp)
.background(color = backgroundColor)
.clickable(onClick = { isSelected = !isSelected })
) {
Text(
text = "Hello",
textAlign = TextAlign.Center
)
}
}
Also I'd say that generally this is a bad practice, because when user increase text size in the phone accessibility settings, your Text may no longer fit your box. Consider using padding instead.
How can i align text to bottom section of a Text component with Jetpack Compose? TextAlign only has Start, End, Left, Center, Right and Justify options.
Text(
text = "First",
textAlign = TextAlign.Start,
modifier = Modifier
.background(Color(0xFF1976D2))
.size(200.dp),
color = Color.White,
)
I want to align Text component's content, each Text has a specific size using modifier.size(x), to align their text to bottom. In the image blue rectangles are Text with different sizes should align the text inside them like in classic Android done with android:gravity.
It is similar to textAlign = TextAlign.x but for bottom.
Setting alignment from a Box aligns Text inside Box or Modifier.align(Alignment.BottomEnd) in BoxScope does what android:layout_gravity does for views, aligns the Text component, not the content of Text component, you can see the difference here.
Code for the blue rectangles in the image is
#Composable
fun BoxExample() {
Box(
modifier = Modifier
.fillMaxWidth()
.height(250.dp)
.background(Color.LightGray)
) {
// This is the one at the bottom
Text(
text = "First",
modifier = Modifier
.background(Color(0xFF1976D2))
.size(200.dp),
color = Color.White,
)
// This is the one in the middle
Text(
text = "Second",
modifier = Modifier
.background(Color(0xFF2196F3))
.size(150.dp),
color = Color.White
)
// This is the one on top
Text(
text = "Third ",
modifier = Modifier
.background(Color(0xFF64B5F6))
.size(100.dp),
color = Color.White
)
}
}
For orange rectangles
#Composable
fun BoxShadowAndAlignmentExample() {
Box(
modifier = Modifier
.fillMaxWidth()
.height(250.dp)
.background(Color.LightGray)
.padding(8.dp)
) {
Box(
modifier = Modifier.shadow(
elevation = 4.dp,
shape = RoundedCornerShape(8.dp)
)
) {
// This is the one at the bottom
Text(
text = "First",
modifier = Modifier
.background(Color(0xFFFFA000))
.size(200.dp),
color = Color.White
)
}
Box(
modifier = Modifier.shadow(
elevation = 4.dp,
shape = RoundedCornerShape(8.dp)
)
.align(Alignment.TopEnd)
) {
// This is the one in the middle
Text(
text = "Second",
modifier = Modifier
.background(Color(0xFFFFC107))
.size(150.dp),
color = Color.White
)
}
val modifier = Modifier.shadow(
elevation = 4.dp,
shape = RoundedCornerShape(8.dp)
)
.align(Alignment.BottomStart)
Box(
modifier = modifier
) {
// This is the one on top
Text(
text = "Third ",
modifier = Modifier
.background(Color(0xFFFFD54F))
.size(100.dp),
color = Color.White
)
}
}
}
Using align modifier you can align child components in specific positions relative to their parents:
Box(modifier = Modifier.fillMaxSize()) {
Text(modifier = Modifier.align(Alignment.BottomEnd),text = "Aligned to bottom end")
Text(modifier = Modifier.align(Alignment.BottomStart),text = "Aligned to bottom start")
Text(modifier = Modifier.align(Alignment.CenterStart),text = "Aligned to start center ")
Text(modifier = Modifier.align(Alignment.TopCenter),text = "Aligned to top center ")
}
Say your component is a Box, place your text within the Box like this:
Box(
modifier = Modifier.fillMaxSize(),
Alignment.BottomStart
) {
Text(
"First",
Modifier.padding(16.dp),
)
}
Basically, you define the section of the component that you want to use in that component, not in the text.
2 years later and I think I have the actual solution for this issue:
for your text composable, add this modifier:
.wrapContentHeight() and for the parameter, you may for example align it to the bottom with Alignment.Bottom
you can try with:
Text(
modifier = Modifier
.height(150.dp)
.wrapContentHeight(Alignment.Bottom)
,
text = "whooopla",
)