Reputation: 1001
I have a Column with some rows, and I want to align the last row at the botton, but this row is never located at the bottom of the screen, it stays right after the previous row:
Column {
// RED BOX
Row(
modifier = Modifier
.fillMaxWidth()
.height(130.dp)
.padding(vertical = 15.dp, horizontal = 30.dp),
verticalAlignment = Alignment.CenterVertically
) {
Column {
Text(
text = stringResource(id = R.string.app_name),
style = TextStyle(fontSize = 40.sp),
color = Color.White
)
Text(
text = stringResource(id = R.string.app_description),
style = TextStyle(fontSize = 13.sp),
fontWeight = FontWeight.Bold,
color = Color.Black
)
}
}
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(15.dp)
)
// GREEN BOX
val currentRoute = currentRoute(navController)
items.forEach { item ->
DrawerItem(item = item, selected = currentRoute == item.route) {
navController.navigate(item.route) {
launchSingleTop = true
}
scope.launch {
scaffoldState.drawerState.close()
}
}
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 15.dp, horizontal = 30.dp),
verticalAlignment = Alignment.Bottom,
horizontalArrangement = Arrangement.Center
) {
Text(
text = BuildConfig.VERSION_NAME,
style = TextStyle(fontSize = 11.sp),
color = Color.Black,
)
}
}
I want to get the same as I show in the picture. I want to have the first row (red), then the second row (green) and then a third row that fits at the bottom of the screen (blue)
Upvotes: 42
Views: 53023
Reputation: 66674
You can use a Spacer(modifier.weight(1f))
between GreenBox and Blue Box to create space between them or you can create your custom column with Layout
function and set y position of last Placeable
as height of Composable
- height of last Composble
Column(modifier = Modifier
.fillMaxHeight()
.background(Color.LightGray)) {
Text(
"First Text",
modifier = Modifier
.background(Color(0xffF44336)),
color = Color.White
)
Text(
"Second Text",
modifier = Modifier
.background(Color(0xff9C27B0)),
color = Color.White
)
Spacer(modifier = Modifier.weight(1f))
Text(
"Third Text",
modifier = Modifier
.background(Color(0xff2196F3)),
color = Color.White
)
}
Result:
Custom Layout
@Composable
private fun CustomColumn(
modifier: Modifier,
content: @Composable () -> Unit
) {
Layout(
modifier = modifier,
content = content
) { measurables, constraints ->
val looseConstraints = constraints.copy(
minWidth = 0,
maxWidth = constraints.maxWidth,
minHeight = 0,
maxHeight = constraints.maxHeight
)
// Don't constrain child views further, measure them with given constraints
// List of measured children
val placeables = measurables.map { measurable ->
// Measure each child
measurable.measure(looseConstraints)
}
// Track the y co-ord we have placed children up to
var yPosition = 0
// Set the size of the layout as big as it can
layout(constraints.maxWidth, constraints.maxHeight) {
// Place children in the parent layout
placeables.forEachIndexed { index, placeable ->
println("Placeable width: ${placeable.width}, measuredWidth: ${placeable.measuredWidth}")
// Position item on the screen
if (index == placeables.size - 1) {
placeable.placeRelative(x = 0, y = constraints.maxHeight - placeable.height)
} else {
placeable.placeRelative(x = 0, y = yPosition)
}
// Record the y co-ord placed up to
yPosition += placeable.height
}
}
}
}
Usage
CustomColumn(
modifier = Modifier
.fillMaxHeight()
.background(Color.LightGray)
) {
Text(
"First Text",
modifier = Modifier
.background(Color(0xffF44336)),
color = Color.White
)
Text(
"Second Text",
modifier = Modifier
.background(Color(0xff9C27B0)),
color = Color.White
)
Text(
"Third Text",
modifier = Modifier
.background(Color(0xff2196F3)),
color = Color.White
)
}
In this example with Layout you should consider how you measure your measureables with Constraints and your total width and height. It requires a little bit practice but you get more unique designs and with less work(more optimised) composables than ready ones. Here i set layout as maxWidth so no matter which width you assign it takes whole width. It's for demonstration you can set max width or height in layout
based on your needs.
Upvotes: 56
Reputation: 145
This approach works for me and also solve if middle content doesn't fit in screen
@Composable
fun FixedTopBottomScrollableMiddleLayout() {
Column(modifier = Modifier.fillMaxSize()) {
// Top Element
Text(
text = "Top Element",
modifier = Modifier.padding(16.dp)
)
// Middle Element (Scrollable)
Box(modifier = Modifier.weight(1f)) {
Text(
text = "This is a long text that will scroll. It demonstrates how to make the middle element scrollable while keeping the top and bottom elements fixed.",
modifier = Modifier.verticalScroll(rememberScrollState())
)
}
// Bottom Element
Text(
text = "Bottom Element",
modifier = Modifier.padding(16.dp)
)
}
}
Upvotes: 0
Reputation: 1072
Another solution is using Scaffold:
Scaffold(
topBar = { /* you can add top bar content */ },
bottomBar = {
Text("Bottom bar",
fontSize = 50.sp,
modifier = Modifier
.fillMaxWidth()
.background(Color.Black),
)
}
) {
Text(
"Main content.",
fontSize = 50.sp,
color = Color.White,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.background(Color.Gray),
)
}
Upvotes: 5
Reputation: 23737
This is what worked for me:
The structure is something like this:
Column // arrangement = Arrangement.SpaceBetween
Column
Row 1
Row 2
Row 3
Row 4
@Preview(showSystemUi = true)
@Composable
fun AlignBottomExample() {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.SpaceBetween
) {
Column() {
Row(
modifier = Modifier.height(100.dp)
.background(Color.Magenta)
.fillMaxWidth(),
) {
Text(text = "Row 1")
}
Row(
modifier = Modifier.height(100.dp)
.background(Color.Cyan)
.fillMaxWidth(),
) {
Text(text = "Row 2")
}
Row(
modifier = Modifier.height(100.dp)
.background(Color.Yellow)
.fillMaxWidth(),
) {
Text(text = "Row 3")
}
}
Row(
modifier = Modifier.height(100.dp)
.background(Color.Green)
.fillMaxWidth(),
) {
Text(text = "Row 4")
}
}
}
Upvotes: 5
Reputation: 363825
You can do it in many ways.
You can use a Column with verticalArrangement = Arrangement.SpaceBetween
assigning a weight(1f,false)
to the last row:
Column(
Modifier.fillMaxHeight(),
verticalArrangement = Arrangement.SpaceBetween) {
//All elements
Column {
// RED BOX
//...
Spacer(
modifier = Modifier
.fillMaxWidth()
.background(Green)
.height(15.dp)
)
//... Green box
}
//LAST ROW
Row(
modifier = Modifier
.weight(1f, false)
) {
//...
}
}
Upvotes: 40