I'm trying the saveLayer and blendMode (I'm using ...
# compose
k
I'm trying the saveLayer and blendMode (I'm using this for the first time I've never used that before even in the previous android UIToolkit). So I followed this tutorial that's originally written for flutter https://stackoverflow.com/a/59650400/4146943 and I ended up with this code in jetpack compose
Copy code
@Composable
fun testBlending2(modifier: Modifier = Modifier) {

    val paint = remember { Paint() }


    Canvas(modifier = modifier, onCanvas = {
        save()
        val rect = Rect(0f, 0f, 100f, 100f)
        drawRect(rect, paint.apply { color = Color.Red })
        saveLayer(Rect.fromLTWH(0f, 0f, size.width.value, size.height.value), paint.apply { BlendMode.multiply })

        drawRect(
                rect.shift(Offset(20f, 20f)),
                paint.apply { color = Color.Blue }
        )
        restore()
        restore()
    })
}
It's supposed to be but it just produces this image:

https://i.stack.imgur.com/q3In0.png

What am I doing wrong?
👍 1
produced Image:
r
Note that you don’t need
saveLayer()
at all in this example
Anyway your problem is most likely that you should be writing:
paint.apply { blendMode = BlendMode.multiply }
You are not assigning the
BlendMode
to anything
k
OOOPS, 😩 what a mistake 😞 how I didn't notice that Thank you
@romainguy I want to create a whole inside the below shape
Copy code
@Composable
fun donat(modifier: Modifier = Modifier) {

    val icingPaint = remember {
        Paint().apply {
            asFrameworkPaint().pathEffect = ComposePathEffect(CornerPathEffect(40f), DiscretePathEffect(60f, 25f))
            color = Color(0xFF53250F)
        }
    }

    Canvas(modifier = modifier, onCanvas = {
        val center = Offset(size.minDimension.value / 2, size.minDimension.value / 2)
        val holePath = Path().apply {
            addOval(Rect.fromCircle(center, size.minDimension.value / 6))
        }

        val icing = Path().apply {
            addOval(Rect.fromCircle(center, size.minDimension.value / 2.5f))
            op(this, holePath, operation = PathOperation.difference).also {
                Log.d("OP RESULT", it.toString())
            }
        }


        drawPath(icing, icingPaint)
    })
}
but it doesn't work, but it works without
asFrameworkPaint().pathEffect = ComposePathEffect(CornerPathEffect(40f), DiscretePathEffect(60f, 25f))
without
asFrameworkPaint().pathEffect = ComposePathEffect(CornerPathEffect(40f), DiscretePathEffect(60f, 25f))
also I can create the whole with
nativeCanvas.clipPath(holePath.asAndroidPath(), Region.Op.DIFFERENCE)
with out removing that pathEffect.
r
It’s probably because your path effect is too wide and covering the hole
k
I changed it to
asFrameworkPaint().pathEffect = DiscretePathEffect(1f, 1f)
but didn't help.
r
Not sure why you keep mentioning Flutter 🙂
saveLayer
basically creates a temporary render target
think of it like a transparent bitmap
and some of the blending modes (like
DstOut
) may only provide the desired results you want when starting from a transparent content
The window of your app is opaque by default, so the alpha value is set to 1
The Android docs show what the different alpha compositing and blend modes do: https://developer.android.com/reference/android/graphics/PorterDuff.Mode
Anyway, so because multiply is not an alpha compositing mode, it works without saving a layer first
but
DstOut
does alpha composition, hence the
saveLayer
Note that
saveLayer
calls have a cost (memory and rendering performance) so use them sparingly (or at least watch performance)
Also, you don’t need the restore simply because Android does have its own restores to prevent mistakes from apps
But better to have a restore for every save
Oh and it wouldn’t make sense to call
saveLayer
for just one of the draw calls
k
@romainguy Thank you for your nice explanation 👍 I got it finally. And about the flutter 😂 because in
BlendMode.kt
there are links to flutter docs and also the docs in that file is equal to to
<https://api.flutter.dev/flutter/dart-ui/BlendMode-class.html>
that was reason for using flutter docs and samples for learning this stuff 😁
r
Ah, that explains 🙂
😁 1
We should fix that :0
348 Views