![](/img/trans.png)
[英]How to draw draw behind the system status bar in a Jetpack Compose Dialog
[英]Jetpack compose - draw background behind text
我想在 Jetpack Compose 中的一些AnnotatedString
后面繪制背景(示例在這里)。 使用視圖系統,我們可以通過編寫自定義文本視圖來實現 - https://medium.com/androiddevelopers/drawing-a-rounded-corner-background-on-text-5a610a95af5 。 有沒有辦法使用 Jetpack Compose 來做到這一點?
我正在查看Text
的draw
修飾符,但我似乎無法弄清楚如何獲取我需要繪制背景的文本的行號或開始/結束。
我應該使用Canvas
而不是Text
嗎?
Text
字符布局的主要信息來源是TextLayoutResult
,它可以通過onTextLayout
參數接收
它的 API 遠非完美。 getPathForRange
返回的Path
正是您所需要的,但與任何其他Path
它無法修改,例如您將無法圓角此路徑,與普通的SpanStyle
背景沒有太大區別
有getBoundingBox
只返回一個字符的幀。 我玩了一下,並獲得了選定范圍的Rect
列表:
fun TextLayoutResult.getBoundingBoxesForRange(start: Int, end: Int): List<Rect> {
var prevRect: Rect? = null
var firstLineCharRect: Rect? = null
val boundingBoxes = mutableListOf<Rect>()
for (i in start..end) {
val rect = getBoundingBox(i)
val isLastRect = i == end
// single char case
if (isLastRect && firstLineCharRect == null) {
firstLineCharRect = rect
prevRect = rect
}
// `rect.right` is zero for the last space in each line
// looks like an issue to me, reported: https://issuetracker.google.com/issues/197146630
if (!isLastRect && rect.right == 0f) continue
if (firstLineCharRect == null) {
firstLineCharRect = rect
} else if (prevRect != null) {
if (prevRect.bottom != rect.bottom || isLastRect) {
boundingBoxes.add(
firstLineCharRect.copy(right = prevRect.right)
)
firstLineCharRect = rect
}
}
prevRect = rect
}
return boundingBoxes
}
現在您可以在Canvas
上繪制這些矩形:
Box(Modifier.padding(10.dp)) {
val text =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
val selectedParts = listOf(
"consectetur adipiscing",
"officia deserunt",
"dolore magna aliqua. Ut enim ad minim veniam, quis nostrud",
"consequat.",
)
var selectedPartPaths by remember { mutableStateOf(listOf<Path>()) }
Text(
text,
style = MaterialTheme.typography.h6,
onTextLayout = { layoutResult ->
selectedPartPaths = selectedParts.map { part ->
val cornerRadius = CornerRadius(x = 20f, y = 20f)
Path().apply {
val startIndex = text.indexOf(part)
val boundingBoxes = layoutResult
.getBoundingBoxesForRange(
start = startIndex,
end = startIndex + part.count()
)
for (i in boundingBoxes.indices) {
val boundingBox = boundingBoxes[i]
val leftCornerRoundRect =
if (i == 0) cornerRadius else CornerRadius.Zero
val rightCornerRoundRect =
if (i == boundingBoxes.indices.last) cornerRadius else CornerRadius.Zero
addRoundRect(
RoundRect(
boundingBox.inflate(verticalDelta = -2f, horizontalDelta = 7f),
topLeft = leftCornerRoundRect,
topRight = rightCornerRoundRect,
bottomRight = rightCornerRoundRect,
bottomLeft = leftCornerRoundRect,
)
)
}
}
}
},
modifier = Modifier.drawBehind {
selectedPartPaths.forEach { path ->
drawPath(path, style = Fill, color = Color.Blue.copy(alpha = 0.2f))
drawPath(path, style = Stroke(width = 2f), color = Color.Blue)
}
}
)
}
fun Rect.inflate(verticalDelta: Float, horizontalDelta: Float) =
Rect(
left = left - horizontalDelta,
top = top - verticalDelta,
right = right + horizontalDelta,
bottom = bottom + verticalDelta,
)
結果:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.