https://kotlinlang.org logo
#compose
Title
# compose
c

Colton Idle

03/09/2021, 4:20 PM
I have a
Red
composable and
Blue
composable that I want to overlap by 35%. The three ways I've thought about doing this is: 1. Have these two in a
Box
, but apply a padding to the top of blue composable that I calculate somehow to be 35% of bottom of red 2. Have these two in a Column, and someone apply a negative padding to a value that I calculate somehow to be 35% of the bottom of red 3. Write a custom layout? (seems scary even though this is supposed to be a lot easier in compose) Anyone have other ideas or an idea of how I would go about this? Right now I just hard coded the padding and it works, but the height of the red square will change and so the hard coded padding idea will fall apart. Edit: Wish there was a way to shrink the preview size in slack. Sorry
l

Lilly

03/09/2021, 5:00 PM
Sounds like a job for #3
1
Have a look here, if you are not familiar with how to create a custom layout:

https://www.youtube.com/watch?v=DDd6IOlH3io

minute 14:55
b

Bradleycorn

03/09/2021, 6:40 PM
No idea if it will help you or not but ... If you scroll up to posts from this weekend. I had a problem where I needed a
Column
to have it's content aligned 35% down from the top of the screen, and @Adam Powell pointed me in the right direction to write a custom
Arrangement
to achieve it. It turned out to be really easy, and you can see the code in the post. In the end, you write something like this:
Copy code
Column(
    modifier = Modifier.fillMaxSize(), 
    verticalArrangement = Arrangement.fromTop(0.35F)) {
 ... 
}
here's a link to the thread that has the code for the
fromTop
arrangement: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1615040563494000
You could probably use the same concept to write an
Arrangement.overlapBy(percent: Float)
method pretty easily
a

Adam Powell

03/09/2021, 7:04 PM
iirc Arrangement doesn't affect the measurement of the items or final container size, so that may not work here
b

Bradleycorn

03/09/2021, 7:13 PM
This seems to work ok?
Copy code
fun Arrangement.overlapBy(@FloatRange(from = 0.0, to = 1.0) percent: Float): Arrangement.Vertical {
    return object: Arrangement.HorizontalOrVertical {
        override val spacing = 0.dp

        override fun Density.arrange(totalSize: Int, sizes: IntArray, outPositions: IntArray) {
            placeItems(percent, totalSize, sizes, outPositions)
        }

        override fun Density.arrange(
            totalSize: Int,
            sizes: IntArray,
            layoutDirection: LayoutDirection,
            outPositions: IntArray
        ) {
            when (layoutDirection) {
                LayoutDirection.Ltr -> placeItems(percent, totalSize, sizes, outPositions)
                else -> {
                    sizes.reverse()
                    placeItems(percent, totalSize, sizes, outPositions)
                    outPositions.reverse()
                }
            }
        }

        private fun placeItems(percent: Float, totalSize: Int, sizes: IntArray, outPositions: IntArray) {
            sizes.foldIndexed(0) { index, acc, size ->
                outPositions[index] = acc
                acc + (size * (1 - percent)).roundToInt()
            }

        }
    }

}
usage:
Copy code
Column(modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.overlapBy(.35F)) {
    Surface(color = Color(0xFFFF0000), modifier = Modifier.fillMaxWidth().requiredHeight(100.dp)) {}
    Surface(color = Color(0xFF0000FF), modifier = Modifier.fillMaxWidth().requiredHeight(100.dp)) {}
    Surface(color = Color(0xFF00FF00), modifier = Modifier.fillMaxWidth().requiredHeight(100.dp)) {}
}
Gives me a screen that looks like:
or, to see the layering, add some alpha to the surface colors:
c

Colton Idle

03/09/2021, 7:42 PM
@Bradleycorn thanks for the snippet. This is almost exactly what I wanted, but like @Adam Powell pointed out...
iirc Arrangement doesn't affect the measurement of the items or final container size, so that may not work here
As Adam says the original size of the view is still actually the same size.
b

Bradleycorn

03/09/2021, 7:48 PM
ah yep. Well, it was worth a shot...
c

Colton Idle

03/09/2021, 7:54 PM
@Bradleycorn thank you for your time. @Adam Powell I guess your opinion is just to stop fearing a custom layout and go with the third option? 😄
👍 2
@ Adam Powell this was about 2 weeks ago, but I asked a "semi" similar question today that you responded to and it got me thinking... there's no way to recreate this effect using that sort of same modifier sequence you showed me today? i.e.
Copy code
.matchParentSize()
 .wrapContentHeight(<http://Alignment.Top|Alignment.Top>)
 .fillMaxHeight(0.5f)
😄 I'm going to hack on this a little tonight, to see if I can save myself from a custom layout.
a

Adam Powell

03/22/2021, 8:13 PM
they key question to ask is, "does this influence the size of the parent?"
The other example from the other thread is one where the answer to that is, "no, it doesn't" - the 50% sized segment and its arrangement doesn't affect the parent size at all.
This however, does. It affects how the min/max constraint sizes need to be treated for the children too.
c

Colton Idle

03/22/2021, 8:26 PM
Thanks Adam. Insightful (and making me think) as always!
6 Views