Last active
May 22, 2024 09:54
-
-
Save grandstaish/18b256b637c2aa0d85aa7e41e3cab9da to your computer and use it in GitHub Desktop.
A raindrop shaped view
This file contains hidden or 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
internal class RaindropView(context: Context) : View(context) { | |
private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { | |
style = Paint.Style.FILL | |
color = Color.WHITE | |
} | |
private val gradientPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { | |
style = Paint.Style.FILL | |
color = Color.WHITE | |
} | |
private val tmpMatrix = Matrix() | |
private val backgroundBounds = RectF() | |
private val insetBounds = RectF() | |
private val raindropPath = Path().apply { | |
// M 13.5 40 | |
// C 20.956 40 27 34.03 27 26.667 | |
// C 27 19.303 19.606 0 13.5 0 | |
// C 7.394 0 0 19.303 0 26.667 | |
// C 0 34.03 6.044 40 13.5 40 | |
// Z | |
moveTo(13.5f, 40f) | |
cubicTo(20.956f, 40f, 27f, 34.03f, 27f, 26.667f) | |
cubicTo(27f, 19.303f, 19.606f, 0f, 13.5f, 0f) | |
cubicTo(7.394f, 0f, 0f, 19.303f, 0f, 26.667f) | |
cubicTo(0f, 34.03f, 6.044f, 40f, 13.5f, 40f) | |
close() | |
} | |
var colors: IntArray? = null | |
set(value) { | |
field = value | |
gradientPaint.updateColors(colors, width) | |
invalidate() | |
} | |
init { | |
elevation = 4.dp.toFloat() | |
outlineProvider = object : ViewOutlineProvider() { | |
override fun getOutline(view: View, outline: Outline) { | |
outline.setConvexPath(raindropPath) | |
} | |
} | |
} | |
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { | |
super.onSizeChanged(w, h, oldw, oldh) | |
// Update the fill paint because the width has changed | |
gradientPaint.updateColors(colors, width) | |
// Set the bounds for the white background and the gradient middle. | |
backgroundBounds.set(0f, 0f, w.toFloat(), h.toFloat()) | |
insetBounds.apply { | |
set(backgroundBounds) | |
inset(2.dp.toFloat(), 2.dp.toFloat()) | |
} | |
// Transform the raindrop path so that it fills the view. | |
val originalPathBounds = RectF(0f, 0f, 27f, 40f) | |
tmpMatrix.setRectToRect(originalPathBounds, backgroundBounds, Matrix.ScaleToFit.FILL) | |
raindropPath.transform(tmpMatrix) | |
invalidateOutline() | |
invalidate() | |
} | |
override fun onDraw(canvas: Canvas) { | |
super.onDraw(canvas) | |
// Draw the white background | |
// No need to scale because the path fills the entire view already! | |
canvas.drawPath(raindropPath, backgroundPaint) | |
// Draw the colorful fill in the middle. | |
// Use a matrix to zoom-out a bit on the canvas before drawing to inset the gradient from the view edges. | |
tmpMatrix.setRectToRect(backgroundBounds, insetBounds, Matrix.ScaleToFit.FILL) | |
canvas.withMatrix(tmpMatrix) { drawPath(raindropPath, gradientPaint) } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment