One of Row items is not displayed in Jetpack Compose view - android

Here's a test composable:
#Preview
#Composable
fun SliderInRow() {
Row {
Text("qwe")
Slider(value = 0f, onValueChange = {})
Text("wer")
}
}
I want a row with a text, a slider and another text. However, the last text composable (wer) is missed:
What am I doing wrong?

Slider is designed to take all width available, same as any view with Modifier.fillMaxWidth does.
That's why he compresses the last view and makes it zero width.
The recommended way to create such a layout is to add Modifier.weight(1f) to the flexible view, Slider in you case. From its documentation:
The parent will divide the horizontal space remaining after measuring unweighted child elements and distribute it according to this weight.
Row {
Text("qwe")
Slider(value = 0f, onValueChange = {}, modifier = Modifier.weight(1f))
Text("wer")
}

Related

Horizontal Scrolling inside LazyColumn in Jetpack Compose

I'm currently trying to recreate a behavior, upon adding a new element to a LazyColumn the items start shifting to the right, in order to represent a Tree and make the elements easier to read.
The mockup in question:
Documentation
Reading through the documentation of Jetpack Compose in Lists and grids I found the following.
Keep in mind that cases where you’re nesting different direction layouts, for example, a scrollable parent Row and a child LazyColumn, are allowed:
Row(
modifier = Modifier.horizontalScroll(scrollState)
) {
LazyColumn {
// ...
}
}
My implementation
Box(Modifier.padding(start = 10.dp)) {
Row(
modifier = Modifier
.horizontalScroll(scrollState)
.border(border = BorderStroke(1.dp, Color.Black))
) {
LazyColumn(
modifier = Modifier.fillMaxWidth()
) {
for (i in 0..25) {
item {
OptionItem(Modifier.padding(start = (i*20).dp))
}
item {
TaskItem(Modifier.padding(start = (i*10).dp))
}
}
}
}
.
.
.
}
OptionItem represents the element with the dot at the beginning, and TaskItem the other one.
When testing the LazyColumn, it appears as if instead of having a fixed size, the size of the column starts growing just after the elements have gone outside the screen, this causes a strange effect.
As you can see in the GIF, the width of the column starts increasing after the elements no longer fit in the screen.
The Question
I want to prevent this effect from happening, so is there any way I could maintain the width of the column to the maximum all the time?
The reason that applying a simple fillMaxWidth will not work because you are telling a composable to stretch to max, but that is impossible because the view itself can stretch indefinitely since it can be horizontally scrollable. I'm not sure why do you want to prevent this behavior but perhaps maybe you want your views to have some initial width then apply the padding, while maintaining the same width. what you can do in such case is simply give your composables a specific width, or what you can do is to get the width of the box and apply them to your composables by width (i used a text in this case)
val localDensity = LocalDensity.current
var lazyRowWidthDp by remember { mutableStateOf(0.dp) }
Box(
Modifier
.padding(start = 10.dp)
.onGloballyPositioned { layoutCoordinates -> // This function will get called once the layout has been positioned
lazyRowWidthDp =
with(localDensity) { layoutCoordinates.size.width.toDp() } // with Density is required to convert to correct Dp
}
) {
val scrollState = rememberScrollState()
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.horizontalScroll(scrollState)
) {
items(25) { i ->
Text(
text = "Hello",
modifier = Modifier
.padding(start = (i * 20).dp)
.width(lazyRowWidthDp)
.border(1.dp, Color.Green)
)
}
items(25) { i ->
Text(
text = "World",
modifier = Modifier
.padding(start = (i * 10).dp)
.width(lazyRowWidthDp)
.border(1.dp, Color.Green)
)
}
}
}
Edit:
you can apply horizontal scroll to the lazy column itself and it will scroll in both directions

How to set component at end of Row in Jetpack Compose? [duplicate]

This question already has answers here:
Compose: wrap text in Row layout, instead of pushing siblings out
(2 answers)
Closed 11 months ago.
I want to set RadioButton component at the end of Row in Jetpack Compose. Tried to using Constraint Layout and moved RadioButton outside the Row but then the RadioButton wasn't centered with other components in Row. What should I do?
Here is my code:
ConstraintLayout {
val (row, button) = createRefs()
Row(
modifier = Modifier
.height(56.dp)
.fillMaxWidth()
.constrainAs(row){
start.linkTo(parent.start)
end.linkTo(parent.end)
},
verticalAlignment = Alignment.CenterVertically
) {
Icon(
/* *** */
)
Text(
text = "mail#gmail.com",
modifier = Modifier.padding(start = 16.dp, end = 16.dp),
)
RadioButton(
/* *** */
)
}
}
What is more i want to cut the Text component if the text is too long (not overlay or underlay the Radio Button)
The simplest solution would be to add a Spacer with Modifier.weight(1f) between your text and the radio button. Row and Column distribute remaining available space between components with a weight Modifier according to their weight. Since there is only one, it will receive all of the remaining space, pushing the radio button to the far right.
For example following code would produce your desired behavior:
Row(modifier = Modifier.height(56.dp).fillMaxWidth(), verticalAlignment = Alignment.CenterVertically){
Icon(Icons.Default.Add,null)
Text("Some text here")
Spacer(Modifier.weight(1f).fillMaxHeight().background(Color.Green)) // height and background only for demonstration
RadioButton(selected = false, onClick = { /*TODO*/ })
}
As I said remaining space is distributed according to the weight of each element, so although this is not what you want to achieve, an example how this might look like
Row(modifier = Modifier.height(56.dp).fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.Add, null)
Spacer(Modifier.weight(1f).fillMaxHeight().background(Color.Red)) // height and background only for demonstration
Text("Some text here")
Spacer(Modifier.weight(4f).fillMaxHeight().background(Color.Green)) // height and background only for demonstration
RadioButton(selected = false, onClick = { /*TODO*/ })
}
will get you
The remaining space after measuring the icon, text and radio button are distributed as 20% to the red Spacer and 80% to the green one, since that is their share of the total weight (1/5 and 4/5)
You could create a Box that fills the rest of the Row and put the Button inside it. You can then align the Button to the right.
Box(modifier = Modifier.fillMaxWidth()) {
RadioButton(modifier = Modifier.align(Alignment.End)){}
}
The same can be achieved with columns instead of the Box, but then every separate element inside the row should have a column wrapping it.

How to apply Materials "Responsive layout grid" to Android Compose?

I would like to align my components based on the Material responsive layout grid, as visualized by from https://material.io/design/layout/responsive-layout-grid.html#columns-gutters-and-margins.
I don't necessarily want my content to be included in a column but rather put baselines on either a start or an end of a column.
A simple example:
// FIXME: What to do?
#Composable
fun example() {
Button(onClick = {
}, text = "Stretch me between start of column 2 and end of column 4"
)
}
My best guess is that I need to use this library somehow: https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/package-summary
But I'm still clueless...
How can I achieve what I want to do in Jetpack Compose?
The requirement is not clear. Please comment if this is not what you are looking for.
To have a button with a width of 2 columns in a 4 column grid system. You can use weight and Spacer to achieve the requirement.
This starts at starting of Column 2 and ends at the ending of Column 3.
Row(
modifier = Modifier.fillMaxWidth(),
) {
Spacer(modifier = Modifier.weight(1f))
Button(
onClick = { /*TODO*/ },
modifier = Modifier
.fillMaxWidth()
.weight(2f),
) {
Text(text = "Center Button")
}
Spacer(modifier = Modifier.weight(1f))
}
Using weight and padding modifiers, along with Spacer we can achieve most of the grid requirements.

Jetpack Compose: How do you position UI elements within their parent with exact (x,y) coordinates?

According to the documentation on custom layouts: "Each UI element has one parent and potentially many children. Each element is also located within its parent, specified as an (x, y) position, and a size, specified as a width and a height."
Let's say I have a Button inside of a Box. How can I specify the exact X and Y position for the Button inside that Box?
By default Box has TopStart alignment, which is the same as android coordinate space start point. To move from that point you can use offset modifier:
Box {
Button(
onClick = { /*TODO*/ },
modifier = Modifier
.offset(x = 100.dp, y = 100.dp)
) {
}
}
For custom Layouts, the story is a bit different. You can read all about that in the Layouts Codelab - https://developer.android.com/codelabs/jetpack-compose-layouts#6
This tells how to design a column by hand.
Example, centering the element in the given constraints.
Layout(
content = {
Button(onClick = { /*TODO*/ }) {
Text("Lorem Ipsum")
}
}
){measurables, constraints ->
//Measuring the First (and only) item with the given constraints and storing the resulting placeable
val placeable = measurables[0].measure(constraints)
layout(constraints.maxWidth, constraints.maxHeight){ // Size of the Layout, can be anything you want, even a number
placeable.place(constraints.maxWidth / 2, constraints.maxHeight / 2) // Placing at net half the distance
//You can also specify the x, y above. That is what it is for.
}
}
And that's all
modifier = Modifier.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
layout(placeable.width, placeable.height) {
// placeable.placeRelative(x.roundToPx(), y.roundToPx())
placeable.place(IntOffset(it.offset.x.roundToInt(), it.offset.y.roundToInt()))
}
}

Fill height for child in Row

I try to achieve this layout but don't really know how:
currently it looks like this:
using this Code:
#Preview(widthDp = 150)
#Composable
fun Item() {
Card(shape = RoundedCornerShape(8.dp)) {
Row {
Box(Modifier.background(Color.Yellow).weight(1f)) {
SomeMoreContentWithUnknownHeight()
}
Box(Modifier.width(20.dp).height(IntrinsicSize.Max).background(Color.Green))
}
}
}
I tried to set the height of the second Box to IntrinsicSize.Max but that didn't change anything. I am currently running Jetpack Compose in Version 1.0.0-beta07
You have to apply Modifier.height(IntrinsicSize.Min) to your Row and .fillMaxHeight() to the 2nd Box.
Something like:
Card(shape = RoundedCornerShape(8.dp)) {
Row(Modifier.height(IntrinsicSize.Min)) {
Box(Modifier
.background(Color.Yellow)
.weight(1f)
) {
//Box(Modifier.height(50.dp))
}
Box(Modifier.width(20.dp)
.fillMaxHeight()
.background(Color.Green)
){
//........
}
}
}
As explained in the doc:
The Row composable's minIntrinsicHeight will be the maximum minIntrinsicHeight of its children. The Green Box element's minIntrinsicHeight is 0 as it doesn't occupy space if no constraints are given; the Yellow Box 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 Yellow Box content. The Green Box will then expand its height to the height constraint given by the Row.

Categories

Resources