https://kotlinlang.org logo
#compose-android
Title
# compose-android
t

tad

10/13/2023, 7:35 PM
I was curious why
drawIntoCanvas { it.nativeCanvas.drawRenderNode(...) }
wasn't drawing anything. Turns out you need to call
RenderNode.setPosition()
before drawing! So a nice cached render modifier for API >= 29 is:
Copy code
fun Modifier.drawCached(): Modifier = drawWithCache {
    val width = size.width.roundToInt()
    val height = size.height.roundToInt()

    val renderNode = RenderNode("drawCached")
    renderNode.setPosition(0, 0, width, height)

    onDrawWithContent {
        val recordingCanvas = renderNode.beginRecording(width, height)
        draw(this, layoutDirection, Canvas(recordingCanvas), size) {
            this@onDrawWithContent.drawContent()
        }
        renderNode.endRecording()
        drawIntoCanvas { it.nativeCanvas.drawRenderNode(renderNode) }
    }
}
This works well for expensive composables in lazy layouts like HorizontalPager, e.g. when layering several layouts in the child pages.
r

romainguy

10/13/2023, 7:47 PM
You could just use a
graphicsLayer{}
?
t

tad

10/13/2023, 7:48 PM
Curiously this outperforms that, but I'll test again
r

romainguy

10/13/2023, 7:48 PM
@Nader Jawad
n

Nader Jawad

10/13/2023, 7:53 PM
They should be identical in performance. Various container composables implicitly place child composables onto their own graphicsLayer as well through the placeWithLayer API
t

tad

10/13/2023, 7:55 PM
I may be placing
graphicsLayer
in the wrong place. The context is a parallax animation inside HorizontalPager, so I wanted to render a Composable to a RenderNode to avoid re-drawing when translating it; however, I am using a custom
Alignment
implementation for the parallax offset instead of using
graphicsLayer { translationX = ... }
. I will rework this and report back.
r

romainguy

10/13/2023, 7:57 PM
graphicsLayer { translationX = ... }
is pretty much free
under the hood it’s just repositioning the
RenderNode
n

Nader Jawad

10/13/2023, 7:57 PM
Custom Alignment can cause additional invalidations and depending on the use case using graphicsLayer translation may help here
r

romainguy

10/13/2023, 7:57 PM
It’s basically what `ListView`/`RecyclerView` do to handle scrolling
t

tad

10/13/2023, 8:30 PM
cool, using
Modifier.layout
with
placeRelativeWithLayer
works pretty well.
I think my performance issues are just rendering the initial layout now.
3 Views