Jojo C
10/25/2024, 2:05 PMStylianos Gakis
10/25/2024, 4:10 PMzIndex
modifier is this:
@Stable
fun Modifier.zIndex(zIndex: Float): Modifier = this then ZIndexElement(zIndex = zIndex)
internal data class ZIndexElement(val zIndex: Float) : ModifierNodeElement<ZIndexNode>() {
override fun create() = ZIndexNode(zIndex)
override fun update(node: ZIndexNode) {
node.zIndex = zIndex
}
override fun InspectorInfo.inspectableProperties() {
name = "zIndex"
properties["zIndex"] = zIndex
}
}
internal class ZIndexNode(var zIndex: Float) : LayoutModifierNode, Modifier.Node() {
override fun MeasureScope.measure(
measurable: Measurable,
constraints: Constraints
): MeasureResult {
val placeable = measurable.measure(constraints)
return layout(placeable.width, placeable.height) {
placeable.place(0, 0, zIndex = zIndex)
}
}
override fun toString(): String = "ZIndexModifier(zIndex=$zIndex)"
}
You can probably make your own modifier which takes in a lambda instead.Stylianos Gakis
10/25/2024, 4:18 PMFloat
instances with () -> Float
, does it work? Give it a shot, I am also curious.
@Stable
private fun Modifier.zIndex(zIndex: () -> Float): Modifier = this then ZIndexElement(zIndex = zIndex)
private data class ZIndexElement(val zIndex: () -> Float) : ModifierNodeElement<ZIndexNode>() {
override fun create() = ZIndexNode(zIndex)
override fun update(node: ZIndexNode) {
node.zIndex = zIndex
}
override fun InspectorInfo.inspectableProperties() {
name = "zIndex"
properties["zIndex"] = zIndex
}
}
private class ZIndexNode(var zIndex: () -> Float) : LayoutModifierNode, Modifier.Node() {
override fun MeasureScope.measure(measurable: Measurable, constraints: Constraints): MeasureResult {
val placeable = measurable.measure(constraints)
return layout(placeable.width, placeable.height) {
placeable.place(0, 0, zIndex = zIndex())
}
}
override fun toString(): String = "ZIndexModifier(zIndex=$zIndex)"
}
I don't know if you'd need to invalidate something yourself. Or if you need to change anything inside inspectableProperties for example, from properties["zIndex"] = zIndex
to properties["zIndex"] = zIndex()
I haven't played a lot around using the new modifier APIs myselfJojo C
10/26/2024, 1:44 AMStylianos Gakis
10/26/2024, 11:55 AMclass Ref(var value: Int)
@Suppress("NOTHING_TO_INLINE")
@Composable
inline fun LogCompositions(message: String) {
val ref = remember { Ref(0) }
SideEffect { ref.value++ }
Log.d("", "Debug Log Compositions: $message ${ref.value}")
}
Then the test code
@Composable
fun Test() {
val transition = rememberInfiniteTransition()
val redIndex by transition.animateFloat(
0f,
2f,
infiniteRepeatable(tween(1000), Reverse),
)
var blueIndex by remember { mutableFloatStateOf(1f) }
LogCompositions("recomp")
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Box(
Modifier
.size(50.dp)
.background(androidx.compose.ui.graphics.Color.Red)
.zIndex(redIndex),
)
Box(
Modifier
.offset { IntOffset(16.dp.roundToPx(), 16.dp.roundToPx()) }
.size(50.dp)
.background(androidx.compose.ui.graphics.Color.Blue)
.zIndex(blueIndex),
)
}
}
This uses the normal zIndex, and logs hundreds of recompositions within just seconds.Stylianos Gakis
10/26/2024, 11:56 AM@Composable
fun Test() {
val transition = rememberInfiniteTransition()
val redIndex by transition.animateFloat(
0f,
2f,
infiniteRepeatable(tween(1000), Reverse),
)
var blueIndex by remember { mutableFloatStateOf(1f) }
LogCompositions("recomp")
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Box(
Modifier
.size(50.dp)
.background(androidx.compose.ui.graphics.Color.Red)
.zIndex { redIndex },
)
Box(
Modifier
.offset { IntOffset(16.dp.roundToPx(), 16.dp.roundToPx()) }
.size(50.dp)
.background(androidx.compose.ui.graphics.Color.Blue)
.zIndex { blueIndex },
)
}
}
It will just do 1 recomposition, and the UI does change where the blue and the red box switch places as the Z index goes over or under 1f.
Run it yourself to check it outJojo C
10/26/2024, 12:11 PMfun comp(idx: () -> Float) {
Box(Modifier.zIndex(idx()))
}
I didnt realize i need to add the Modifier zIndex lambda implementation myself, 😅
Thank you anyways!Stylianos Gakis
10/26/2024, 12:48 PM() -> T
is a key to deferring reads indeed, some more context in this old discussion https://kotlinlang.slack.com/archives/CJLTWPH7S/p1637855772048800?thread_ts=1637854750.046000&cid=CJLTWPH7S