android - Jetpack Compose 中的可扩展文本
问题描述
所以我正在使用这样的Text()
组合:
Text(
text = "this is some sample text that is long and so it is
ellipsized",
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
并且它正确地省略了文本:
问题是我想See More
在省略号末尾添加一个标签,提示用户展开可见文本框。我将如何添加它?
解决方案
要解决这个问题,您需要使用onTextLayout
get TextLayoutResult
:它包含有关绘制文本状态的所有信息。
让它适用于多行是一项棘手的任务。为此,您需要计算椭圆文本和“...查看更多”文本的大小,然后,当您拥有这两个值时,您需要计算需要删除多少文本,以便“...查看更多”非常适合在行尾:
@Composable
fun ExpandableText(
text: String,
modifier: Modifier = Modifier,
minimizedMaxLines: Int = 1,
) {
var cutText by remember(text) { mutableStateOf<String?>(null) }
var expanded by remember { mutableStateOf(false) }
val textLayoutResultState = remember { mutableStateOf<TextLayoutResult?>(null) }
val seeMoreSizeState = remember { mutableStateOf<IntSize?>(null) }
val seeMoreOffsetState = remember { mutableStateOf<Offset?>(null) }
// getting raw values for smart cast
val textLayoutResult = textLayoutResultState.value
val seeMoreSize = seeMoreSizeState.value
val seeMoreOffset = seeMoreOffsetState.value
LaunchedEffect(text, expanded, textLayoutResult, seeMoreSize) {
val lastLineIndex = minimizedMaxLines - 1
if (!expanded && textLayoutResult != null && seeMoreSize != null
&& lastLineIndex + 1 == textLayoutResult.lineCount
&& textLayoutResult.isLineEllipsized(lastLineIndex)
) {
var lastCharIndex = textLayoutResult.getLineEnd(lastLineIndex, visibleEnd = true) + 1
var charRect: Rect
do {
lastCharIndex -= 1
charRect = textLayoutResult.getCursorRect(lastCharIndex)
} while (
charRect.left > textLayoutResult.size.width - seeMoreSize.width
)
seeMoreOffsetState.value = Offset(charRect.left, charRect.bottom - seeMoreSize.height)
cutText = text.substring(startIndex = 0, endIndex = lastCharIndex)
}
}
Box(modifier) {
Text(
text = cutText ?: text,
maxLines = if (expanded) Int.MAX_VALUE else minimizedMaxLines,
overflow = TextOverflow.Ellipsis,
onTextLayout = { textLayoutResultState.value = it },
)
if (!expanded) {
val density = LocalDensity.current
Text(
"... See more",
onTextLayout = { seeMoreSizeState.value = it.size },
modifier = Modifier
.then(
if (seeMoreOffset != null)
Modifier.offset(
x = with(density) { seeMoreOffset.x.toDp() },
y = with(density) { seeMoreOffset.y.toDp() },
)
else
Modifier
)
.clickable {
expanded = true
cutText = null
}
.alpha(if (seeMoreOffset != null) 1f else 0f)
)
}
}
}
推荐阅读
- c++ - 在 Cygwin 上使用 -std=c++11 进行编译会隐藏可用的系统调用
- amazon-mws - 从 API 获取亚马逊 MWS 货件状态
- amazon-web-services - Dynamodb boto3 dynamodbstreams get_records
- javascript - 使用格式将表单复制到剪贴板
- javascript - 为子元素动态添加属性
- java - 使用 Recycle View 时无法在 Android Emulator 中看到应用程序栏
- c++ - SSE2 将压缩 RGB 转换为 RGBA 像素(每 3 个字节后添加第 4 个 0xFF 字节)
- javascript - 将 Firestore 文档添加到 observable
- javascript - 多个元素的 indexOf() 方法的替代方法
- python - 了解类以及导致此属性错误的原因