I'm wondering if there's a better way to clip a ca...
# compose
z
I'm wondering if there's a better way to clip a canvas drawing to a Shape without using the clip modifier. I'm applying this drawWithCache modifier to a Box containing a draggable thumb component. So I can't use the clip modifier on the single Box, because then it clips the thumb as well. I was also able to fix it with an additional Box seperating the Canvas and the thumb, but I want to keep it to just one Box. I currently have this code which works, but is it the best way to apply a clip?
Copy code
.drawWithCache {
                val path = shape.createOutline(size.toSize(), layoutDirection, this)
                val graphicsLayer = obtainGraphicsLayer()
                val saturationBrush = Brush.verticalGradient(listOf(Color.Transparent, Color.Black))
                val hueBrush = Brush.horizontalGradient(
                    listOf(
                        Color.Transparent,
                        Color.hsv(color().hue, 1f, 1f)
                    )
                )

                graphicsLayer.apply {
                    setOutline(path)
                    compositingStrategy = CompositingStrategy.Offscreen // fixes weird transparent corners
                    clip = true
                    record {
                        drawRect(Color.White)
                        drawRect(hueBrush)
                        drawRect(saturationBrush)
                    }
                }

                onDrawBehind {
                    drawLayer(graphicsLayer)
                }
            }
r
Using a layer here is overkill and expensive. Did you try just using the clip*() methods on Canvas/DrawScope?
You could also just draw with the shape, instead of clipping rectangles. That's probably the most efficient thing to do
z
I saw the clipPath method but I'm only able to figure out how to convert the shape to an Outline
r
Are you creating the shape yourself?
z
No, it's just an instance of androidx.compose.ui.Shape like RoundedCornerShape(8.dp)
r
Right but if it's something you instantiate yourself, you could create a Path instead. You can look a the graphics-shape library in androidx to do it easily
l
Alternatively, with the
Outline
you can use
Path.addOutline()
and then clip that
☝️ 1
z
Oh I didn't know that was a method. With that I'm able to get it to clip, but I'm not sure how to apply the offscreen rendering to fix the corners. Adding it as using the graphicsLayer modifier has no effect
Copy code
.drawWithCache {
                val outline = shape.createOutline(size.toSize(), layoutDirection, this)
                val path = Path().apply { addOutline(outline) }
                val hueBrush = Brush.horizontalGradient(
                    listOf(
                        Color.Transparent,
                        Color.hsv(color().hue, 1f, 1f)
                    )
                )

                onDrawBehind {
                    clipPath(path) {
                        drawRect(Color.White)
                        drawRect(hueBrush)
                        drawRect(saturationBrush)
                    }
                }
            }
r
In your case you don't even need clipPath at all. You could just draw the path (or a rounded rect directly) 3 times