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

Mihai Hrincescu

01/24/2021, 4:29 PM
Hello everyone ! Is there a reason why we cannot create our own custom brushes by extending Brush()?
j

jim

01/24/2021, 5:09 PM
cc @Nader Jawad
n

Nader Jawad

01/24/2021, 8:56 PM
Yup, Brush is used to configure a "fill" which is either a color or a shader only. Within the DrawScope API we have a very tightly managed Paint object used internally that we update across every draw call. This avoids the Paint management done by devs in the existing android framework as it it allocated and cached in the appropriate location. Question for @Mihai Hrincescu is what did you intend to extend a brush parameter for? Brush is not intended to apply arbitrary paint parameters. In fact Paint is more of an implementation detail of compose and in a majority of cases can be completely avoided. By leveraging this pattern we only have a single Paint object used for an entire composition (1 per AndroidComposeView instance)
m

Mihai Hrincescu

01/24/2021, 9:01 PM
The use case I wanted was to disable antialiasing when drawing a grid of 1 pixel wide straight lines. I know I can also use the old API's with a paint object I manage myself I was just curios about the reasons behind it.
n

Nader Jawad

01/24/2021, 9:02 PM
DrawScope gives you access to raw pixel values not density independent pixels so you can ensure you are drawing on a pixel boundary
Otherwise you can use
DrawScope.drawIntoCanvas
to get access to a canvas and you can bring your own Paint object
m

Mihai Hrincescu

01/24/2021, 9:05 PM
So how would I go about doing that?
n

Nader Jawad

01/24/2021, 9:10 PM
Copy code
@Composable
fun Foo() {
    Canvas(modifier = Modifier.size(100.dp)) {
        drawIntoCanvas { canvas ->
            // Don't recommend, should create and cache this Paint object
            // otherwise it will be allocated on every draw call
            val paint = Paint().apply {
                style = PaintingStyle.Stroke
                color = Color.Black
                isAntiAlias = false
            }
            canvas.drawLine(Offset.Zero, Offset(size.width, 0f), paint)
        }
    }
}
Something like this
But you shouldn't need to enforce antialiasing if you have hold pixel sized strokes and you are always drawing on pixel boundaries
m

Mihai Hrincescu

01/24/2021, 9:19 PM
I know how to draw lines without the antialiasing using the paint object, I was just wandering if there was a way to do this using the new drawScope api's that is why I was trying to extend the Brush() so I could pass one extra parameter to tell the paint to disable the antialiasing . So rounding the coordinates to nearest Int used to draw the lines would fix this without needing to disable antialiasing?
n

Nader Jawad

01/24/2021, 9:21 PM
That would be the more ideal approach. Disabiling anti-aliasing leads to visual artifacts that don't look great which is why the default is on. Brush is not intended to be a generic applier of paint params but only configures the color/shader parameters. The others are explicitly configured on each DrawScope API call
👍 1
m

Mihai Hrincescu

01/24/2021, 9:24 PM
That clears a lot of confusion for me, and actually makes things simpler. Thx a lot for the answer.
👍 1
The fact that all the draw calls take floats really threw me off a little bit there.
n

Nader Jawad

01/24/2021, 9:27 PM
This is consistent with the android.graphics.Canvas API to drawLines which also takes in floats. It's to ensure you can get visual correctness even when content doesn't land on pixel boundaries and anti-aliasing helps here
m

Mihai Hrincescu

01/24/2021, 9:34 PM
It all makes sense now, I didn't really noticed that before because I would just disable antialiasing to get the result I wanted and I guess I was just lucky I didn't run into some weird artefacts.