All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.outsidesource.oskitcompose.modifier.Shadow.kt Maven / Gradle / Ivy

package com.outsidesource.oskitcompose.modifier

import androidx.compose.runtime.Immutable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import com.outsidesource.oskitcompose.canvas.kmpBlur

fun Modifier.innerShadow(
    blur: Dp,
    spread: Dp = 0.dp,
    color: Color = Color.Black,
    shape: Shape = RectangleShape,
    offset: DpOffset = DpOffset.Zero,
    drawOverContent: Boolean = false,
) = (if (!drawOverContent) graphicsLayer { alpha = .99f } else this) // This forces Android to use alpha compositing
    .drawWithContent {
        if (drawOverContent) drawContent()

        val rect = Rect(Offset.Zero, size)
        val paint = Paint()

        drawIntoCanvas {
            paint.color = color
            paint.isAntiAlias = true

            if (drawOverContent) it.saveLayer(rect, paint)

            val fillOutline = shape.createOutline(size, layoutDirection, this)
            it.drawOutline(paint = paint, outline = fillOutline)

            paint.blendMode = BlendMode.DstOut

            if (blur.toPx() > 0) paint.kmpBlur(blur.toPx() / 2)

            translate(
                left = spread.toPx() + offset.x.toPx(),
                top = spread.toPx() + offset.y.toPx()
            ) {
                val shadowSize = size.copy(width = size.width - (spread.toPx() * 2), size.height - (spread.toPx() * 2))
                val shadowOutline = shape.createOutline(shadowSize, layoutDirection, this)
                it.drawOutline(paint = paint, outline = shadowOutline)
            }
        }

        if (!drawOverContent) drawContent()
    }

data class InnerShadow(
    val blur: Dp,
    val spread: Dp = 0.dp,
    val color: Color = Color.Black,
    val shape: Shape = RectangleShape,
    val offset: DpOffset = DpOffset.Zero,
    val drawOverContent: Boolean = false,
)

fun Modifier.outerShadow(
    blur: Dp,
    spread: Dp = 0.dp,
    color: Color = Color.Black,
    shape: Shape = RectangleShape,
    offset: DpOffset = DpOffset.Zero,
) = drawBehind {
    val paint = Paint()

    drawIntoCanvas {
        paint.color = color
        paint.isAntiAlias = true

        if (blur.toPx() > 0) if (blur.toPx() > 0) paint.kmpBlur(blur.toPx() / 2)
        val shadowSize = size.copy(width = size.width + (spread.toPx() * 2), size.height + (spread.toPx() * 2))
        val outline = shape.createOutline(shadowSize, layoutDirection, this)

        translate(
            left = -(spread.toPx()) + offset.x.toPx(),
            top = -(spread.toPx()) + offset.y.toPx()
        ) {
            it.drawOutline(paint = paint, outline = outline)
        }
    }
}

@Immutable
data class OuterShadow(
    val blur: Dp,
    val spread: Dp = 0.dp,
    val color: Color = Color.Black,
    val shape: Shape = RectangleShape,
    val offset: DpOffset = DpOffset.Zero,
)




© 2015 - 2025 Weber Informatics LLC | Privacy Policy