How do I get these circles to line up perfectly? I...
# compose
c
How do I get these circles to line up perfectly? It looks a little off. Code in thread
I currently have a composable called my dot. I need to draw a circle depending on the size of the modifier passed in. That part is easy, but I also need to "cut out" another circle in the middle of that circle that's half the size. Currently im faking the "cut out" by drawing white. but even in that case it looks off. thoughts?
Copy code
@Composable
private fun MyDot(modifier: Modifier) {
    BoxWithConstraints(
        modifier = modifier,
        contentAlignment = Center
    ){
        Box(Modifier.size(this.maxWidth).background(Color.Red, CircleShape))
        Box(Modifier.size(this.maxWidth / 2).background(Color.White, CircleShape))
    }
}
r
Probably a rounding error due to positioning on integer pixels
Easier to control with custom drawing
Use a Canvas instead of 2 Box?
c
K. thought id be able to get away with it. but back to canvas land i go. lol
I'm not confident in my canvas skills... but thanks to rigaroos help... i think it's this?
Copy code
Canvas(modifier = modifier, onDraw = {
    drawCircle(Color.Red)
    drawCircle(
        color = Color.White,
        radius = size.minDimension / 4,
    )
})
looks better i think
And one last question in this sense. is there an easy way to go from my Canvas code above, to actually have this be a mask/clip instead of faking it with Color.White?
looks like maybe this
Copy code
Box(
    modifier
        .graphicsLayer {
            compositingStrategy = CompositingStrategy.Offscreen
        }
        .drawWithContent {
            drawCircle(Color.Red)
            drawCircle(
                color = Color.Black,
                radius = size.minDimension / 4,
                blendMode = BlendMode.Clear
            )
        }
)
r
Yeah just like that
e
if you do
Copy code
Canvas(modifier = modifier) {
    val path = Path()
    val outer = Rect(center, size.minDimension / 2)
    path.arcTo(outer, 0f, 180f, true)
    path.arcTo(outer, 180f, 180f, false)
    val inner = Rect(center, size.minDimension / 4)
    path.arcTo(inner, 180f, -180f, true)
    path.arcTo(inner, 0f, -180f, false)
    drawPath(path, Color.Red)
}
you don't need any compositing strategy
c
Is compositing strategy bad? or less performant than the above? just curious if i should prefer one over the other
e
https://developer.android.com/reference/android/graphics/Canvas#saveLayer(android.graphics.RectF,%20android.graphics.Paint)
This behaves the same as save(), but in addition it allocates and redirects drawing to an offscreen rendering target.
Note: this method is very expensive, incurring more than double rendering cost for contained content. Avoid using this method when possible and instead use a
hardware layer
on a View to apply an xfermode, color filter, or alpha, as it will perform much better than this method.
is effectively what it does
r
Composition strategy isn't bad but it uses memory and more bandwidth every time the content needs updated
saveLayer() is similar but worse because it isn't cached
Composition strategy is more akin to View.setLayerType()
@ephemient Also in your solution you don't need to use arcs, you can do two addCircle
e
ah, so it'll hold a bitmap?
r
You just need to give them each a different winding
e
yeah I missed that helper
r
No it doesn't hold a bitmap, it holds a GPU texture
e
oh neat. so it's not really that much worse performance, just more memory usage and copying
r
Well if the layer doesn't need updated it's extremely efficient to draw on screen
c
Very intersting indeed. on the same topic of "clipping" a shape out of a shape. If I had to implement something like this, where it's a rectangle clipped out... what approach would you reccommend?
r
You can do the same path trick
Create a rect then add a round rect with the opposite winding
Or a layer + a clear to punch out a hole
Or you could use a 9patch/vector 9patch ^^
e
that's just an oddly-shaped scrim, isn't it?
o
Why not to draw that dot with border modifier and circle shape? 🤔
r
If all you need is the stroked circle then yeah that works too