Create Vertical Divider Jetpack Compose - android

How to create vertical dividers with Jetpack Compose? I try to use Spacer and Box to do it, but it doesn't show up at all. Here is what i tried:
Box(
modifier = Modifier
.fillMaxHeight()
.width(2.dp)
.background(color = Color.Black)
)
But that doesn't work at all. So how to do vertical divider in Jetpack Compose?

You can use the Divider composable with the width(xx.dp) modifier applying an intrinsic measurements to its parent container.
Something like:
Row(Modifier
.height(IntrinsicSize.Min) //intrinsic measurements
.fillMaxWidth()
.background(Color.Yellow)) {
Text("First Text")
Divider(
color = Color.Red,
modifier = Modifier
.fillMaxHeight() //fill the max height
.width(1.dp)
)
Text("Second text")
}
As explained in the doc:
The Row composable's minIntrinsicHeight will be the maximum minIntrinsicHeight of its children. The Divider element's minIntrinsicHeight is 0 as it doesn't occupy space if no constraints are given; the TextField minIntrinsicHeight will be that of the content given a specific width. Therefore, the Row element's height constraint will be the max minIntrinsicHeight of the TextFields content. The Divider will then expand its height to the height constraint given by the Row.

Here is a VerticalDivider Composable, which you can use the same way as the built-in Divider horizontal one.
#Composable
fun VerticalDivider(
modifier: Modifier = Modifier,
color: Color = MaterialTheme.colors.onSurface.copy(alpha = DividerAlpha),
thickness: Dp = 1.dp
) {
Box(
modifier
.fillMaxHeight()
.width(thickness)
.background(color = color)
)
}
private const val DividerAlpha = 0.12f

You can use BOX ,SPACER or DIVIDER to create a vertical divider
Row(modifier = Modifier.height(20.dp)) {
Text("TEXT 1")
Box(
modifier = Modifier
.fillMaxHeight()
.width(2.dp)
.background(Color.Red)
)
Spacer(
modifier = Modifier
.fillMaxHeight()
.width(2.dp)
.background(Color.Black)
)
Divider(color = Color.Blue, modifier = Modifier
.fillMaxHeight()
.width(2.dp))
Text("TEXT 2")
}
Code result:

Related

Setting LazyColumn Item Height to Maximum Available in Jetpack Compose [duplicate]

I have a compose card and inside a row with circle views, I need to make it so the last item in this row is half shown only. Is there a easy way to achieve this without measuring the screen width after everything is drawn and then modify the padding for the row items dynamically to achieve it?)
If you need to calculate the number of elements depending on the size of the cell contents, it is impossible to do this without real measurements.
But if you know exactly how many elements you need to display, you can use Modifier.fillParentMaxWidth with the desired fraction. This is only available in lazy views like LazyRow.
Things are a bit more complicated with spacings: usually contentPadding is used to offset the first element, which reduces the parent size, depending on which Modifier.fillParentPaxMaxWidth calculates the actual value. Also, if you apply it to both start and end, you won't get the desired result. That's why I apply it only to start, and create an equivalent effect at the end with another item.
I also manually surround the Spacers item instead of using Arrangement.spacedBy, because the spacers should be inside the Modifier.fillParentMaxWidth too.
val spacing = 20.dp
val halfSpacing = spacing / 2
val shape = RoundedCornerShape(20)
LazyRow(
contentPadding = PaddingValues(start = halfSpacing),
modifier = Modifier
.padding(30.dp)
.border(1.dp, color = Color.Black, shape = shape)
.clip(shape)
.padding(vertical = 20.dp)
) {
items(10) {
Row(
Modifier
.fillParentMaxWidth(1f / 3.5f)
) {
Spacer(Modifier.size(halfSpacing))
Box(
Modifier
.weight(1f)
.aspectRatio(1f)
.background(Color.Blue, shape = CircleShape)
)
Spacer(Modifier.size(halfSpacing))
}
}
item {
Spacer(Modifier.size(halfSpacing))
}
}
Result:
LazyColumn variant:
val spacing = 20.dp
val halfSpacing = spacing / 2
val shape = RoundedCornerShape(20)
LazyColumn(
contentPadding = PaddingValues(top = halfSpacing),
modifier = Modifier
.padding(30.dp)
.border(1.dp, color = Color.Black, shape = shape)
.clip(shape)
.padding(horizontal = 20.dp)
) {
items(10) {
Column(
Modifier
.fillParentMaxHeight(1f / 3.5f)
) {
Spacer(Modifier.size(halfSpacing))
Box(
Modifier
.weight(1f)
.aspectRatio(1f)
.background(Color.Blue, shape = CircleShape)
)
Spacer(Modifier.size(halfSpacing))
}
}
item {
Spacer(Modifier.size(halfSpacing))
}
}

Spacing views inside a compose row so the last view always is half shown

I have a compose card and inside a row with circle views, I need to make it so the last item in this row is half shown only. Is there a easy way to achieve this without measuring the screen width after everything is drawn and then modify the padding for the row items dynamically to achieve it?)
If you need to calculate the number of elements depending on the size of the cell contents, it is impossible to do this without real measurements.
But if you know exactly how many elements you need to display, you can use Modifier.fillParentMaxWidth with the desired fraction. This is only available in lazy views like LazyRow.
Things are a bit more complicated with spacings: usually contentPadding is used to offset the first element, which reduces the parent size, depending on which Modifier.fillParentPaxMaxWidth calculates the actual value. Also, if you apply it to both start and end, you won't get the desired result. That's why I apply it only to start, and create an equivalent effect at the end with another item.
I also manually surround the Spacers item instead of using Arrangement.spacedBy, because the spacers should be inside the Modifier.fillParentMaxWidth too.
val spacing = 20.dp
val halfSpacing = spacing / 2
val shape = RoundedCornerShape(20)
LazyRow(
contentPadding = PaddingValues(start = halfSpacing),
modifier = Modifier
.padding(30.dp)
.border(1.dp, color = Color.Black, shape = shape)
.clip(shape)
.padding(vertical = 20.dp)
) {
items(10) {
Row(
Modifier
.fillParentMaxWidth(1f / 3.5f)
) {
Spacer(Modifier.size(halfSpacing))
Box(
Modifier
.weight(1f)
.aspectRatio(1f)
.background(Color.Blue, shape = CircleShape)
)
Spacer(Modifier.size(halfSpacing))
}
}
item {
Spacer(Modifier.size(halfSpacing))
}
}
Result:
LazyColumn variant:
val spacing = 20.dp
val halfSpacing = spacing / 2
val shape = RoundedCornerShape(20)
LazyColumn(
contentPadding = PaddingValues(top = halfSpacing),
modifier = Modifier
.padding(30.dp)
.border(1.dp, color = Color.Black, shape = shape)
.clip(shape)
.padding(horizontal = 20.dp)
) {
items(10) {
Column(
Modifier
.fillParentMaxHeight(1f / 3.5f)
) {
Spacer(Modifier.size(halfSpacing))
Box(
Modifier
.weight(1f)
.aspectRatio(1f)
.background(Color.Blue, shape = CircleShape)
)
Spacer(Modifier.size(halfSpacing))
}
}
item {
Spacer(Modifier.size(halfSpacing))
}
}

Overlap two Box jetpack compose

I'm trying to overlap two Box or perhaps is better to use Row on this case.
My design is one Row overlapped with another one, and I've wrapped it on a Column, is that correct?
This is the design, what I'd like to have is the rectangle of the top be the same size of the one below and then move it some pixels as you can see in the image, but they should have the same width but not the same height.
Is it okay if the hierarchy is :
Column
Box (the one of the top)
Row
Box (the one of the bottom)
Row (inside there is text and it's all the same align)
......
I've faced with this some days ago and I solved it using ConstraintLayout.
What I had to do is :
Add implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-beta02" to build.gradle
Wrap every Box in a ConstraintLayout { .. }
Inside each Box add a Modifier.constrainAs to align the Top Bottom Start End as you want.
If you want the first box be the same width as the second one without hardcoding the dps you should use width = Dimension.fillToConstraints
fillToConstraints - the layout will expand to fill the space defined by its constraints in that dimension.
Basic example without hard-coding :
ConstraintLayout() {
val (title, description) = createRefs()
Box(
modifier = Modifier
.padding(start = 28.dp)
.background(color = Red)
.padding(
horizontal = 16.dp,
)
.constrainAs(title) {
top.linkTo(parent.top)
start.linkTo(parent.start)
end.linkTo(parent.end)
width = Dimension.fillToConstraints
}
) {
Text(text = "Hello World")
}
Box(
modifier = Modifier
.padding(end = 4.dp)
.background(Color.Magenta)
.padding(bottom = 5.dp, start = 8.dp, end = 16.dp, top = 4.dp)
.constrainAs(description) {
top.linkTo(title.top, margin = 16.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
bottom.linkTo(parent.bottom)
}
) {
Text(text = "Skizo-ozᴉʞS rules")
}
}
Now you have to play with the padding according to your UI and adapt it, result is something like this :
This is way using BoxWithConstraints and not using fixed width and height:
BoxWithConstraints(
Modifier
.background(color = Color.Blue)
.padding(20.dp)) {
val boxWidth = this.maxWidth
Box(
modifier = Modifier
.width(boxWidth - 10.dp)
.background(Color.Red)
) {
Text(text = "Hello Android")
}
Column() {
Spacer(modifier = Modifier
.height(10.dp)
.width(10.dp))
Row( ) {
Spacer(modifier = Modifier.width(10.dp))
Box(
modifier = Modifier
.width(boxWidth)
.zIndex(2f)
.background(Color.Yellow)
) {
Text("aa", modifier = Modifier.background(color = Color.Green))
}
}
}
}
In order for the Composables to overlap, you should put them in the same Box. Try this out:
Box(modifier = Modifier.size(width = 300.dp, height = 100.dp)) {
Row(modifier = Modifier
.size(width = 200.dp, height = 50.dp)
.background(color = Color.Blue)
.align(Alignment.TopEnd)) {}
Row(modifier = Modifier
.size(width = 200.dp, height = 70.dp)
.background(color = Color.Red)
.align(Alignment.BottomStart)) {}
}
You can achieve this in many ways,
#Composable
fun BoxOverBox() {
Box(
modifier = Modifier.fillMaxSize()
.background(Color.White),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier
.width(200.dp)
.height(50.dp)
.background(Color.Red)
)
Box(
modifier = Modifier
.width(200.dp)
.height(50.dp)
.zIndex(2f)
.graphicsLayer {
translationX = -50f
translationY = 50f
}
.background(Color.Blue)
)
}
}
I think you must use "matchParentSize" modifier that is avaliabele inside BoxScope, I mean inside Box composable, that modifer measure other children size except itself when it has join the composable at first time to apply the same size to itself.
you can see this modifier in documentation
https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/BoxScope#(androidx.compose.ui.Modifier).matchParentSize()

Box doesn't fill max size - Jetpack Compose

My PersonalDataBox() doesn't fill max available space even if there is .fillMaxSize()
There is a empty space between my box and the bottom of the screen. I want to fill my whole screen with Box(). It looks like my box has .fillWrapHeight(). Parent of the box is also .fillMaxSize() and it works correctly - fills max height.
#Composable
private fun PersonalDataBox(user: User) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(vertical = 10.dp)
.clip(RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp))
.background(Color.Red)
.padding(horizontal = 25.dp, vertical = 15.dp)
) {
Column(modifier = Modifier.fillMaxSize()) {
Text(
text = stringResource(R.string.personal_data),
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
fontSize = 16.sp,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colors.primary
)
listOf(
Pair(stringResource(R.string.name), user.name),
Pair(stringResource(R.string.surname), user.surname),
Pair(stringResource(R.string.e_mail), user.email),
).forEach {
InputField(it)
}
}
}
}
I pulled down your code and it actually renders in the whole screen just fine--so I'm assuming you have your PersonalDatabox in a compose view with infinite height such as a LazyColumn.
Check out the documentation about constraints here
Specifically:
Most commonly, when measured with unbounded Constraints, these children will fallback to size themselves to wrap their content, instead of expanding to fill the available space (this is not always true as it depends on the child layout model, but is a common behavior for core layout components).
In other words, if the constraint is infinite, then .fillMaxSize will default to wrapping content.
To get around this, you can make the constraint equal to the height of the Lazy Column by using fillParentMaxHeight.
This only works if you're using a LazyColumn, though. Otherwise, if you set the height specifically or measure the screen you can accomplish the same thing.
Here's an example of what that might look like.
LazyColumn() {
item {
Column(modifier = Modifier.fillParentMaxHeight(1f)) {
PersonalDataBox(User(name = "John", surname = "Robless", "coolemail#email.com"))
}
}
}
Your Box has the following modifiers:
modifier = Modifier
.fillMaxSize()
.padding(vertical = 10.dp)
.clip(RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp))
.background(Color.Red)
.padding(horizontal = 25.dp, vertical = 15.dp)
The important ones are
.padding(vertical = 10.dp)
.padding(horizontal = 25.dp, vertical = 15.dp)
There are two padding modifiers adding a total of 25.dp padding to the top and bottom of your Box, remove these and it should fix your issue

how to add space between grid items in jetpack compose

I am currently trying to implement a gridview, it consists of 2 columns. I know i can implement my own grid view using columns and rows, but i just want to use existing approach although it is experimental.
#Composable
fun MyGridScreen() {
LazyVerticalGrid(cells = GridCells.Fixed(2), modifier = Modifier.fillMaxSize(),contentPadding = PaddingValues(12.dp)) {
items(15) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(10.dp)
.height(80.dp)
.background(Color.Red)
.aspectRatio(1f)
) {
Text("Grid item $it", color = Color.White)
}
}
}
}
Below is the result i achieved. I can't put space below the item :(
You need to set verticalArrangement and horizontalArrangement properties on the LazyVerticalGrid composable.
This will space the items by 10.dp in both the vertical and horizontal axis.
#Composable
fun MyGridScreen() {
LazyVerticalGrid(
cells = GridCells.Fixed(2),
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(12.dp),
verticalArrangement = Arrangement.spacedBy(10.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp
) {
items(15) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(10.dp)
.height(80.dp)
.background(Color.Red)
.aspectRatio(1f)
) {
Text("Grid item $it", color = Color.White)
}
}
}
}
Padding is exactly what you need in this case. But you need to understand that in compose modifiers order means a lot. By moving background modifier in between padding and sizes modifiers, you'll get what you need. And clickable ripple will work the same.
Check out more how modifiers order works: https://stackoverflow.com/a/65698101/3585796
.padding(10.dp)
.background(Color.Red)
.height(80.dp)
.aspectRatio(1f)
p.s. if you need your items to be a square, just put your box in one more box. Looks like width of items in LazyVerticalGrid gets overridden by the grid to fill max width, not sure if that's a bug or a feature.

Categories

Resources