Skip to content

Instantly share code, notes, and snippets.

@Pluu
Created August 15, 2024 14:30
Show Gist options
  • Save Pluu/a513dad61faf367197e1b04af6894201 to your computer and use it in GitHub Desktop.
Save Pluu/a513dad61faf367197e1b04af6894201 to your computer and use it in GitHub Desktop.
BulletText.kt
///////////////////////////////////////////////////////////////////////////
// Row style BasicText
///////////////////////////////////////////////////////////////////////////
@Composable
fun BulletTextRow(
text: String,
modifier: Modifier = Modifier,
style: TextStyle = LocalTextStyle.current,
bulletRadius: Dp = 2.dp,
bulletSpace: Dp = bulletRadius * 2,
bulletColor: Color = if (style.color == Color.Unspecified) {
Color.Black
} else {
style.color
}
) {
val textMeasurer = rememberTextMeasurer()
val textLayoutResult = remember(style, textMeasurer) {
textMeasurer.measure(text = text.split(System.lineSeparator()).first(), style = style)
}
val startFirstLine = textLayoutResult.getLineStart(0).toFloat()
val bulletCenterX = startFirstLine + bulletRadius.toPx
val bulletCenterY = textLayoutResult.lineVerticalMiddle(0)
Row(
modifier = modifier.semantics(
mergeDescendants = true,
properties = {}
)
) {
if (text.isNotEmpty()) {
Canvas(
modifier = Modifier
.padding(end = bulletSpace)
.size(bulletRadius * 2)
) {
drawCircle(color = bulletColor, center = Offset(bulletCenterX, bulletCenterY))
}
}
BasicText(text, style = style)
}
}
private fun TextLayoutResult.lineVerticalMiddle(line: Int): Float {
return (getLineBottom(line) - getLineTop(line)) / 2
}
///////////////////////////////////////////////////////////////////////////
// Single BasicText
///////////////////////////////////////////////////////////////////////////
@Composable
fun BulletText(
text: String,
modifier: Modifier = Modifier,
style: TextStyle = LocalTextStyle.current,
bulletRadius: Dp = 2.dp,
bulletSpace: Dp = bulletRadius * 2,
bulletColor: Color = if (style.color == Color.Unspecified) {
Color.Black
} else {
style.color
}
) {
var bulletCenterY by remember {
mutableFloatStateOf(0f)
}
val bulletSizePx = bulletRadius.toPx
val textIndent = (bulletRadius * 2 + bulletSpace).textSp
BasicText(
buildAnnotatedString {
withStyle(
ParagraphStyle(
textIndent = TextIndent(
firstLine = textIndent,
restLine = textIndent
)
)
) {
append(text)
}
},
modifier = modifier
.drawBehind {
drawCircle(
bulletColor,
radius = bulletSizePx,
center = Offset(bulletSizePx, bulletCenterY)
)
},
style = style,
onTextLayout = {
bulletCenterY = it.lineVerticalMiddle(0)
}
)
}
@Preview(showBackground = true)
@Composable
internal fun BulletTextPreview() {
ComposeSamplesTheme {
Column(modifier = Modifier.padding(12.dp)) {
var bulletSize by remember { mutableIntStateOf(2) }
val bulletRadius by remember {
derivedStateOf { bulletSize.dp }
}
Text("Bullet Radius (${bulletRadius})", fontSize = 10.sp)
Slider(
bulletSize.toFloat(),
onValueChange = { bulletSize = it.toInt() },
valueRange = 0f..20f,
)
var bulletSpace by remember { mutableIntStateOf(2) }
val bulletSpaceDp by remember {
derivedStateOf { bulletSpace.dp }
}
Text("Bullet Space (${bulletSpaceDp})", fontSize = 10.sp)
Slider(
bulletSpace.toFloat(),
onValueChange = { bulletSpace = it.toInt() },
valueRange = 0f..20f
)
Text("BulletText with Row")
BulletTextRow(
"가나다라마바사아자차카타파하ABCDEFGHIJKLMNOPQRSTUVWXYZ".chunked(3).joinToString(" "),
modifier = Modifier.fillMaxWidth(),
style = TextStyle(fontSize = 30.sp),
bulletRadius = bulletRadius,
bulletSpace = bulletSpaceDp
)
Spacer(Modifier.height(12.dp))
HorizontalDivider()
Spacer(Modifier.height(12.dp))
Text("BulletText")
BulletText(
"가나다라마바사아자차카타파하ABCDEFGHIJKLMNOPQRSTUVWXYZ".chunked(3).joinToString(" "),
modifier = Modifier.fillMaxWidth(),
style = TextStyle(fontSize = 30.sp),
bulletRadius = bulletRadius,
bulletSpace = bulletSpaceDp
)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment