SuperAPI AI 工具集

expandable-and-linkified-text

前端与建站

查看项目

更新于 10-17 16:15

技能介绍

本资料给出的是 Kotlin/Jetpack Compose 中两个文本交互需求的实现要点:长文本折叠展开,以及文本内子串可点击。二者在视觉上像同一个功能,但实现机制互不依赖。

用途 在聊天、评论、简介等场景中,把长文本限制为若干行,并在溢出时提供“更多/收起”;同时让文本中的时间戳、URL 等片段可以单独点击。

主要能力与实现方式 折叠:通过 Text 的 maxLines 控制显示行数,在 onTextLayout 回调中读取 result.hasVisualOverflow 判断是否真的溢出。溢出只由布局阶段决定,因为同一字符串在不同宽度、字体、字号缩放和翻译下换行结果不同。确认溢出后,用 getLineEnd(collapsedMaxLine - 1) 取得最后一个可见字符的位置,再从字符串中裁掉与“更多”标签等长的字符并去掉尾部空白和句点,使标签本身落在行内而不被截断。状态(是否展开、是否可点击、最后字符索引)用 remember 保存。 链接:用 buildAnnotatedString 构建文本,遍历合并后的时间戳和 URL 正则匹配,为每个匹配片段 pushStringAnnotation 打上标签并附加链接样式;点击时通过 pointerInput 和 detectTapGestures 拿到坐标,用 getOffsetForPosition 转成字符偏移,再以 getStringAnnotations 查询该位置上的标注并触发回调。时间戳片段携带自身原始文本(如“1:02:33”),由点击处理方决定如何解析使用。

适用场景 适合在 Compose 界面中实现带“展开/收起”的长描述、带可点击时间戳的视频字幕或章节标记、带可点击 URL 的富文本段落。

限制与注意事项

  • 溢出是测量结果而非字符长度,按字符数设阈值只在特定宽度和字号下成立。
  • hasVisualOverflow 在布局回调中才可得,折叠在第一帧正确,但“更多”标签会在下一帧出现。
  • remember 不带 key 时,可点击标志和最后字符索引会在组件复用于另一条文本时残留,需以 text 作为 key。
  • 回调可能在行数少于折叠行数时触发,getLineEnd 需要做保护和回退。
  • 同一组件上同时挂容器 clickable 和 detectTapGestures 会导致点击先被文本消费,外层展开失效;应二选一:整块切换不带标注,或文本持有标注、另设独立标签控制展开。
  • getOffsetForPosition 返回最近字符偏移,行尾空白处的点击也会命中结束该行的片段。
  • 标注字符串应在 remember(text) 内构建,避免每次重组都扫描正则,也避免在 findAll 的懒序列上对其匹配结果重复调用 count 导致重复扫描。
  • Character.isWhitespace 只在 JVM 目标下可用,共享代码应使用 Kotlin 的 isWhitespace。

验证方式 资料给出 grep 命令,用于查找使用 hasVisualOverflow 的折叠组件,以及只写不读或只读不写的标注调用;并建议手动缩小窗口观察“更多”是否出现且文字在句子中间结束,展开收起两次检查标志位残留,点击链接确认整块没有同时展开。