-
-
Save L10n42/d74b30af3dc0ae50358dc845363dfebc to your computer and use it in GitHub Desktop.
3D Border in Jetpack Compose
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.graphics.BlurMaskFilter | |
import android.graphics.PorterDuff | |
import android.graphics.PorterDuffXfermode | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.draw.drawWithContent | |
import androidx.compose.ui.geometry.Size | |
import androidx.compose.ui.geometry.toRect | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.graphics.Outline | |
import androidx.compose.ui.graphics.Paint | |
import androidx.compose.ui.graphics.PaintingStyle | |
import androidx.compose.ui.graphics.Shape | |
import androidx.compose.ui.graphics.drawOutline | |
import androidx.compose.ui.graphics.drawscope.DrawScope | |
import androidx.compose.ui.graphics.drawscope.Stroke | |
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.dp | |
/** | |
* Data class representing the style of a convex effect. | |
* | |
* @property blur The blur radius for the shadow and glare effects. | |
* @property offset The offset distance for the shadow and glare effects. | |
* @property glareColor The color used for the glare effect. | |
* @property shadowColor The color used for the shadow effect. | |
*/ | |
data class ConvexStyle( | |
val blur: Dp = 3.dp, | |
val offset: Dp = 2.dp, | |
val glareColor: Color = Color.White.copy(0.64f), | |
val shadowColor: Color = Color.Black.copy(0.64f) | |
) | |
/** | |
* Extension function for Modifier to draw a border with a convex effect. | |
* | |
* @param color The color of the border. | |
* @param shape The shape of the border. | |
* @param strokeWidth The width of the border stroke. | |
* @param convexStyle The style of the convex effect applied to the border. | |
*/ | |
fun Modifier.convexBorder( | |
color: Color, | |
shape: Shape, | |
strokeWidth: Dp = 8.dp, | |
convexStyle: ConvexStyle = ConvexStyle() | |
) = this.drawWithContent { | |
val adjustedSize = Size(size.width - strokeWidth.toPx(), size.height - strokeWidth.toPx()) | |
val outline = shape.createOutline(adjustedSize, layoutDirection, this) | |
drawContent() | |
val halfStrokeWidth = strokeWidth.toPx() / 2 | |
translate(halfStrokeWidth, halfStrokeWidth) { | |
drawOutline( | |
outline = outline, | |
color = color, | |
style = Stroke(width = strokeWidth.toPx()) | |
) | |
} | |
with(convexStyle) { | |
drawConvexBorderShadow(outline, strokeWidth, blur, -offset, -offset, shadowColor) | |
drawConvexBorderShadow(outline, strokeWidth, blur, offset, offset, glareColor) | |
} | |
} | |
private fun DrawScope.drawConvexBorderShadow( | |
outline: Outline, | |
strokeWidth: Dp, | |
blur: Dp, | |
offsetX: Dp, | |
offsetY: Dp, | |
shadowColor: Color | |
) = drawIntoCanvas { canvas -> | |
val shadowPaint = Paint().apply { | |
this.style = PaintingStyle.Stroke | |
this.color = shadowColor | |
this.strokeWidth = strokeWidth.toPx() | |
} | |
canvas.saveLayer(size.toRect(), shadowPaint) | |
val halfStrokeWidth = strokeWidth.toPx() / 2 | |
canvas.translate(halfStrokeWidth, halfStrokeWidth) | |
canvas.drawOutline(outline, shadowPaint) | |
shadowPaint.asFrameworkPaint().apply { | |
xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT) | |
maskFilter = BlurMaskFilter(blur.toPx(), BlurMaskFilter.Blur.NORMAL) | |
} | |
shadowPaint.color = Color.Black | |
canvas.translate(offsetX.toPx(), offsetY.toPx()) | |
canvas.drawOutline(outline, shadowPaint) | |
canvas.restore() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment