Jetpack Compose : 超简单实现文本展开和收起
作者:访客发布时间:2023-12-27分类:程序开发学习浏览:105
导读:前言文本展开和收起功能可以在需要显示较长文本或内容丰富的情况下,提供更好的用户体验和页面可读性,同时减少页面的冗余信息。可以说是发中常见的功能之一。需要实现的点文本超出最大显...
前言
文本展开和收起功能可以在需要显示较长文本或内容丰富的情况下,提供更好的用户体验和页面可读性,同时减少页面的冗余信息。可以说是发中常见的功能之一。
需要实现的点
- 文本超出最大显示行数时尾部显示"...展开"
- 点击"...展开"时显示全部文本并且尾部显示"...收起"
看看Text为我们提供了啥
查看Text的源码很容易看到overflow和maxLines两个属性。
@Composable
fun Text(
// 要显示的文本内容
text: String,
// Modifier修饰符
modifier: Modifier = Modifier,
// 文本内容溢出处理方式:Clip、Ellipsis、Visible
overflow: TextOverflow = TextOverflow.Clip,
// 最大文本行数
maxLines: Int = Int.MAX_VALUE,
// 计算新文本布局时执行的回调。
onTextLayout: (TextLayoutResult) -> Unit = {},
// 文本的样式配置
style: TextStyle = LocalTextStyle.current
)
当我们的overflow设置为"Ellipsis"且文本超出最大行数时显示"..."。
因此我们的思路很简单,当文本控件显示"..."时在其尾部盖上"...展开",伪代码如下:
Box {
Text()
Text(
text = "...展开",
modifier = Modifier
.graphicsLayer {
translationX = ellipsisLeft
translationY = ellipsisBottom - size.height
}
)
}
如何获得文本内容溢出后的位置
还好Text控件提供了onTextLayout回调返回TextLayoutResult,这里贴对我们有用的几个方法:
class TextLayoutResult constructor(
val layoutInput: TextLayoutInput,
val multiParagraph: MultiParagraph,
val size: IntSize
) {
val lineCount: Int get() = multiParagraph.lineCount
fun isLineEllipsized(lineIndex: Int): Boolean = multiParagraph.isLineEllipsized(lineIndex)
fun getLineTop(lineIndex: Int): Float = multiParagraph.getLineTop(lineIndex)
fun getLineBottom(lineIndex: Int): Float = multiParagraph.getLineBottom(lineIndex)
/**
* 获取指定行右侧X坐标
*/
fun getLineRight(lineIndex: Int): Float = multiParagraph.getLineRight(lineIndex)
/**
* 获取指定位置字符的水平偏移量
*/
fun getHorizontalPosition(offset: Int, usePrimaryDirection: Boolean): Float =
multiParagraph.getHorizontalPosition(offset, usePrimaryDirection)
/**
* 获取指定偏移量最接近的字符位置。
*/
fun getOffsetForPosition(position: Offset): Int =
multiParagraph.getOffsetForPosition(position)
}
ellipsisBottom可以通过getLineBottom直接获取取。
ellipsisLeft就相对要麻烦些,我们先要获取指定行右侧X坐标再减去ellipsisText的width。
先计算下ellipsisText的width,好在compose为我们提供非常便捷的api这里直接贴代码:
val ellipsisMeasure = rememberTextMeasurer()
val ellipsisLayoutResult = ellipsisMeasure.measure(
text = ellipsisText,
style = style
)
val ellipsisWidth = ellipsisLayoutResult.size.width
但是直接使用会出现文字部分被覆盖的情况,所以我们通过该值先获取指定偏移量最接近的字符位置,再通过获取指定位置字符的水平偏移量得到真正的值。
val ellipsisLeft = it.getHorizontalPosition(
it.getOffsetForPosition(
Offset(
it.getLineRight(it.lineCount - 1) - ellipsisWidth,
it.getLineTop(it.lineCount - 1)
)
), true
)
完整代码
@Composable
fun EllipsisText(
text: AnnotatedString,
color: Color,
backgroundColor: Color,
fontSize: TextUnit = TextUnit.Unspecified,
lineHeight: TextUnit = TextUnit.Unspecified,
maxLines: Int = Int.MAX_VALUE,
inlineContent: Map<String, InlineTextContent> = mapOf(),
onTextLayout: (TextLayoutResult) -> Unit = {},
ellipsisText: String = "...全文",
ellipsisColor: Color = colorResource(R.color.blue),
onClick: () -> Unit = {},
onEllipsisClick: () -> Unit = {},
) {
val style = TextStyle.Default.copy(color = color, fontSize = fontSize)
var ellipsisBottom by remember { mutableFloatStateOf(0f) }
var ellipsisLeft by remember { mutableFloatStateOf(0f) }
val ellipsisMeasure = rememberTextMeasurer()
val ellipsisLayoutResult = ellipsisMeasure.measure(
text = ellipsisText,
style = style
)
val ellipsisWidth = ellipsisLayoutResult.size.width
Box(modifier = Modifier.animateContentSize()) {
Text(
text = text,
modifier = Modifier
.clickable(
onClick = onClick,
indication = null,
interactionSource = remember { MutableInteractionSource() }
)
.background(backgroundColor),
lineHeight = lineHeight,
overflow = TextOverflow.Ellipsis,
maxLines = maxLines,
inlineContent = inlineContent,
onTextLayout = {
val offset = if (maxLines == Int.MAX_VALUE) 0 else ellipsisWidth
ellipsisBottom = it.getLineBottom(it.lineCount - 1)
ellipsisLeft = it.getHorizontalPosition(
it.getOffsetForPosition(
Offset(
it.getLineRight(it.lineCount - 1) - offset,
it.getLineTop(it.lineCount - 1)
)
), true
)
if (ellipsisLeft + ellipsisWidth > it.size.width) {
ellipsisLeft = it.getHorizontalPosition(
it.getOffsetForPosition(
Offset(
(it.size.width - ellipsisWidth).toFloat(),
it.getLineTop(it.lineCount - 1)
)
), true
)
}
onTextLayout(it)
},
style = style
)
Text(
text = "$ellipsisText ",
modifier = Modifier
.graphicsLayer {
translationX = ellipsisLeft
translationY = ellipsisBottom - size.height
}
.clickable { onEllipsisClick() }
.background(backgroundColor),
style = style.copy(color = ellipsisColor)
)
}
}
如何使用
var ellipsis by remember { mutableStateOf(false) }
var expand by remember { mutableStateOf(false) }
EllipsisText(
text = buildAnnotatedString {
append(
"I am happy to join with you today in what will go down in history as the greatest demonstration for freedom in the history of our nation."
)
},
color = colorResource(R.color.text_333),
backgroundColor = colorResource(R.color.background),
fontSize = 14.sp,
maxLines = if (expand) Int.MAX_VALUE else 2,
onTextLayout = {
ellipsis = it.isLineEllipsized(it.lineCount - 1)
},
ellipsisText = if (expand) {
"...收起"
} else if (ellipsis) {
"...展开"
} else {
""
}
) {
expand = !expand
}
Thanks
以上就是本篇文章的全部内容,如有问题欢迎指出,我们一起进步。
如果觉得本篇文章对您有帮助的话请点个赞让更多人看到吧,您的鼓励是我前进的动力。
谢谢~~
源代码地址
- EllipsisText.kt · miaowmiaow/fragmject
推荐阅读
- Jetpack Compose : 从改造你的登录页面开始 - 掘金 (juejin.cn)
- Jetpack Compose : 一学就会的自定义下拉刷新&加载更多 - 掘金 (juejin.cn)
- Jetpack Compose : 优雅的使用WebView - 掘金 (juejin.cn)
- Jetpack Compose : 一文学会嵌套滚动NestedScrollConnection - 掘金 (juejin.cn)
- Jetpack Compose : 超简单实现滚轮控件(WheelPicker) - 掘金 (juejin.cn)
- 程序开发学习排行
-
- 1鸿蒙HarmonyOS:Web组件网页白屏检测
- 2HTTPS协议是安全传输,为啥还要再加密?
- 3HarmonyOS鸿蒙应用开发——数据持久化Preferences
- 4记解决MaterialButton背景颜色与设置值不同
- 5鸿蒙HarmonyOS实战-ArkUI组件(RelativeContainer)
- 6鸿蒙HarmonyOS实战-ArkUI组件(Stack)
- 7[Android][NDK][Cmake]一文搞懂Android项目中的Cmake
- 8Android广播如何解决Sending non-protected broadcast问题
- 9鸿蒙HarmonyOS实战-ArkUI组件(mediaquery)
- 最近发表
-
- WooCommerce最好的WordPress常用插件下载博客插件模块的相关产品
- 羊驼机器人最好的WordPress常用插件下载博客插件模块
- IP信息记录器最好的WordPress常用插件下载博客插件模块
- Linkly for WooCommerce最好的WordPress常用插件下载博客插件模块
- 元素聚合器Forms最好的WordPress常用插件下载博客插件模块
- Promaker Chat 最好的WordPress通用插件下载 博客插件模块
- 自动更新发布日期最好的WordPress常用插件下载博客插件模块
- WordPress官方最好的获取回复WordPress常用插件下载博客插件模块
- Img to rss最好的wordpress常用插件下载博客插件模块
- WPMozo为Elementor最好的WordPress常用插件下载博客插件模块添加精简版