This question already has an answer here:
Compose Layout: Align relative to centered item (eg. toRightOf)
(1 answer)
Closed 1 year ago.
I have the following layout
This has the text aligned to the center and the image is aligned to the end of the parent. I'm in the process of learning Jetpack compose and was wondering if it is possible for the children of the row to specify their alignment (gravity)?
I can achieve the above layout using a constraint layout.
Here is my current solution:
ConstraintLayout(
modifier = Modifier.fillMaxWidth()
) {
val (logo, avatar) = createRefs()
Text(
text = "Some Text",
modifier = Modifier.constrainAs(logo) {
centerHorizontallyTo(parent)
centerVerticallyTo(parent)
}
)
Image(
imageVector = Icons.Rounded.Person,
contentDescription = stringResource(id = R.string.profile_pic),
modifier = Modifier
.size(60.dp)
.clip(CircleShape)
.background(Color.LightGray)
.padding(4.dp)
.constrainAs(avatar) {
start.linkTo(logo.end)
linkTo(logo.end, parent.end, bias = 1f)
}
)
}
Can this also be achieved using a Row/Column setup?
Look so simple.
Column+Row:
Column(Modifier.fillMaxWidth()) {
Row(
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
){
Box(Modifier.weight(1f))
Text(
"Simple text",
textAlign = TextAlign.Center,
modifier = Modifier.weight(1f)
)
Icon(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "Icon",
Modifier.weight(1f)
)
}
}
Box:
Box(Modifier.fillMaxWidth()) {
Text(
"Simple text",
textAlign = TextAlign.Center,
modifier = Modifier.align(Alignment.Center)
)
Icon(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "Icon",
modifier = Modifier.align(Alignment.CenterEnd)
)
}
Related
I have such a view
#Composable
fun LongText() {
ConstraintLayout(
) {
val (leftImg, headerTitle, rightImg) = createRefs()
Image(
modifier = Modifier
.constrainAs(leftImg) {
top.linkTo(parent.top)
start.linkTo(parent.start)
bottom.linkTo(parent.bottom)
},
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = ""
)
Text(
text = "LONGTEXTLONGTEXTLONGTEXTLONGTEXTLONGTEXT",
textAlign = TextAlign.Left,
modifier = Modifier
.padding(start = 8.dp)
.constrainAs(headerTitle) {
start.linkTo(leftImg.end)
top.linkTo(parent.top)
end.linkTo(rightImg.start)
bottom.linkTo(parent.bottom)
},
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = Color.Red
)
Image(
modifier = Modifier
.constrainAs(rightImg) {
top.linkTo(parent.top)
end.linkTo(parent.end)
bottom.linkTo(parent.bottom)
},
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = ""
)
}
}
There are two problems that I am trying to find out:
Why maxLines & overflow doesn't work for Text view? I expect that verylong text will be collapsed with three dots once it reaches the image on the right, what is the problem here?
maxLines = 1,
overflow = TextOverflow.Ellipsis
Result:
Why align doesn't work for short text? I mean according to this line textAlign = TextAlign.Left I expect that short text appear on the left, close to the left image, however instead I have this text in the middle
Result:
You can use a simple Row applying a weight(1f) modifier to the Text
Row(Modifier.fillMaxWidth()) {
Image(
painter = painterResource(id = R.drawable.xxx),
contentDescription = ""
)
Text(
text = "LONGTEXTLONGTEXTLONGTEXTLONGTEXTLONGTEXT",
textAlign = TextAlign.Left,
modifier = Modifier
.padding(start = 8.dp).weight(1f),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = Color.Red
)
Image(
painter = painterResource(id = R.drawable.ic_xxx),
contentDescription = ""
)
}
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'm trying to achieve this view with jetpack compose:
I create a row consisting of an image with a weight 0.7 and a column that contains those smaller images with a weight 0.3.
But there is always padding at bottom of the column and they won't align perfectly.
My code:
#Composable
fun TrendingSection() {
Row(horizontalArrangement = Arrangement.SpaceBetween) {
Image(
painter = painterResource(id = R.drawable.shadmehr),
contentDescription = "First trending music",
modifier = Modifier
.weight(0.7f)
.padding(4.dp)
.clip(RoundedCornerShape(16.dp))
)
Column(
verticalArrangement = Arrangement.SpaceAround,
modifier = Modifier
.weight(0.3f)
) {
Image(
painter = painterResource(id = R.drawable.shadmehr),
contentDescription = "First trending music",
modifier = Modifier
.padding(4.dp)
.clip(RoundedCornerShape(16.dp))
)
Image(
painter = painterResource(id = R.drawable.shadmehr),
contentDescription = "First trending music",
modifier = Modifier
.padding(4.dp)
.clip(RoundedCornerShape(16.dp))
)
}
}
}
Anyone knows what is the problem or know a better solution for doing this?
Result:
RI am developing an Android app using jetpack compose.
Here is a very basic UI component:
I want to add a button on the right side.
But if the name is very long, the button is gone.
My code is here:
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = rememberImagePainter(data = profileImg),
contentDescription = null,
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
)
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier.weight(1F) // I set the weight in here but it doesn't work.
) {
Text(
text = "very very very very very very very long name",
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = "3 minutes ago",
)
}
}
Row {
Button()
Button()
}
}
How can I show the right button correctly?
You need to actually provide that weight to Row containing your Text & make sure you don't cover the entire width. e.g don't do just 1f.
You can do something like this; (This is done with compose_version = '1.0.1')
#Composable
fun Item() {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.weight(0.7f)
) {
Image(
painter = painterResource(R.drawable.ic_launcher_background),
contentDescription = null,
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
)
Column(
verticalArrangement = Arrangement.Center,
) {
Text(
text = "very very very very very very very long name",
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = "3 minutes ago",
)
}
}
Button(
onClick = {}, modifier = Modifier
.wrapContentWidth()
.weight(0.3f)
) {
Text(text = "Button")
}
}
}
Output:
Here is a working code (I've removed useless Row, it's simpler that way)
#Composable
fun Test() {
Row(
modifier = Modifier.fillMaxWidth,
horizontalArrangement = Arrangement.spacedBy(5.dp),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = rememberImagePainter(data = profileImg),
contentDescription = null,
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
)
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier.weight(1f) // I set the weight in here but it doesn't work.
) {
Text(
text = "very very very very very very very long name",
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = "3 minutes ago",
)
}
Button(onClick = { }) {
Text(text = "Btn1")
}
Button(onClick = { }) {
Text(text = "Btn2")
}
}
}
Even though the other question are right I am going to explain your mistake, to better understand what is going on.
So you need:
A Row() which will contain those 3:
Image
Column
and a Row with the two buttons
In other words something like:
Row() {
Image()
Column(weight:1f)
Row()
}
Your mistake is that you created a Row with two other Rows without weights and you get this weird output.
So if you simply delete your outer Row and move your Row of buttons like so it will work:
Items seem to have fixed height inside Column.
I'm trying to show multiple rows of dynamic height inside the column, and the items of those rows also having dynamic height.
I have tried wrapping the Column inside the box, but that doesn't work.
Box {
Column(
modifier = Modifier
.fillMaxSize()
) {
Image(
painter = painterResource(id = R.drawable.background_home),
contentDescription = "",
contentScale = ContentScale.FillBounds,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.3f)
)
Spacer(modifier = Modifier.height(10.dp))
List()
Spacer(modifier = Modifier.height(10.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp)
) {
Text(
text = "My Days",
style = TextStyle(
fontStyle = FontStyle.Normal,
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold
)
)
Text(text = "Red Sun")
}
MyAnotherList(
Modifier
.fillMaxWidth()
.fillMaxHeight(0.6f)
.padding(10.dp)
.horizontalScroll(rememberScrollState())
)
Spacer(modifier = Modifier.height(10.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp)
) {
Text(
text = "My Other Days",
style = TextStyle(
fontStyle = FontStyle.Normal,
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold
)
)
Text(text = "Blue Sun")
}
MyOtherList()
}
TopBar()
}
Trying to achieve something like this, but all the rows will have dynamic height
Is there a way that I can provide dynamic height to the items inside scrollable columns.