Created
August 25, 2021 18:04
-
-
Save rock3r/a9f53217ed3663729108604870df2e4a to your computer and use it in GitHub Desktop.
Bubble shape — the hard way, because why not.
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
internal class SpeechBubbleShape( | |
private val cornerRadius: Dp, | |
@Px private val stemPosition: Float, | |
private val stemSize: Dp | |
) : Shape { | |
private val bubblePath = Path() | |
override fun createOutline( | |
size: Size, | |
layoutDirection: LayoutDirection, | |
density: Density | |
): Outline = with(density) { | |
Outline.Generic(createSpeechBubblePath(size, cornerRadius.toPx(), stemPosition, stemSize.toPx())) | |
} | |
private fun createSpeechBubblePath( | |
size: Size, | |
@Px cornerRadius: Float, | |
@Px stemPosition: Float, | |
@Px stemSize: Float | |
): Path { | |
// /\ | |
// / \ | |
// _____/ \__________________ | |
// / \ | |
// | | | |
// | | | |
// | | | |
// \_____________________________/ | |
bubblePath.apply { | |
reset() | |
val cornerDiameter = cornerRadius * 2 | |
// Top left rounded corner | |
arcTo( | |
rect = Rect(left = 0f, top = stemSize, right = cornerDiameter, bottom = stemSize + cornerDiameter), | |
startAngleDegrees = 180f, | |
sweepAngleDegrees = 90f, | |
forceMoveTo = false | |
) | |
// Left-hand part of the top edge of the rounded rect | |
lineTo(x = stemPosition - (stemSize / 2), y = stemSize) | |
// Stem | |
lineTo(x = stemPosition, y = 0f) | |
lineTo(x = stemPosition + (stemSize / 2), y = stemSize) | |
// Right-hand part of the top edge of the rounded rect | |
lineTo(x = size.width - cornerRadius, y = stemSize) | |
// Top right rounded corner | |
arcTo( | |
rect = Rect(left = size.width - cornerDiameter, top = stemSize, right = size.width, bottom = stemSize + cornerDiameter), | |
startAngleDegrees = 270f, | |
sweepAngleDegrees = 90f, | |
forceMoveTo = false | |
) | |
// Right edge | |
lineTo(x = size.width, y = size.height - cornerRadius) | |
// Bottom right rounded corner | |
arcTo( | |
rect = Rect(left = size.width - cornerDiameter, top = size.height - cornerDiameter, right = size.width, bottom = size.height), | |
startAngleDegrees = 0f, | |
sweepAngleDegrees = 90f, | |
forceMoveTo = false | |
) | |
// Bottom edge | |
lineTo(x = cornerRadius, y = size.height) | |
// Bottom left rounded corner | |
arcTo( | |
rect = Rect(left = 0f, top = size.height - cornerDiameter, right = cornerDiameter, bottom = size.height), | |
startAngleDegrees = 90f, | |
sweepAngleDegrees = 90f, | |
forceMoveTo = false | |
) | |
// Left edge (by cheating) | |
close() | |
} | |
return bubblePath | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment