Ellipsize — 是一种文本截断机制,不是在像素级别裁剪行,而是在末尾或中间添加省略号符号 (…),向用户指示文本未完全显示在容器中。此技术用于标题、按钮、联系人列表以及任何宽度受限的 UI 组件。根据 Google Material Design 指南,ellipsize 是 TextView 和 UILabel 的标准行为,支持四种截断模式:开头、中间、结尾和滚动文本。
要点
Ellipsize(来自英语 ellipsis — 省略号)— 是一种显示超出容器尺寸文本的技术。不是简单地在边界处裁剪行(clip),ellipsize 会添加省略号符号(Unicode U+2026),向用户指示存在隐藏内容。
这个术语在 Android SDK 中已经确立,其中 android:ellipsize 属性决定了 TextView 在溢出时的行为。在 iOS 上,类似的功能称为 truncation(截断),通过 NSLineBreakMode 进行管理。在 Web 上,使用 CSS 属性 text-overflow,值为 ellipsis。
Ellipsize 的主要目标是 告知用户文本已被缩短。与像素级裁剪不同(单词可能被切成两半),ellipsize 保证了可读性:省略号放在完整单词或字符之后,不会将其打断。这符合 Material Design 和 Human Interface Guidelines 的原则。
只要容器宽度固定且文本长度动态,就应使用 ellipsize:文章标题、表格单元格、带标签的按钮、列表中的联系人、面包屑导航和文件路径。
在 Android 中,ellipsize 通过 XML 中的 android:ellipsize 属性或代码中的 setEllipsize() 方法进行配置。有四种可用模式,每种模式决定文本从哪一侧被截断。
END 模式(大多数情况下的默认值)截断行尾并将省略号放在容器右侧。START 模式截断开头 — 省略号在左侧,可见文本在右侧。MIDDLE 截断中间,保留行的开头和结尾可见。MARQUEE 模式 — 文本的动画滚动,不显示省略号,文本循环滚动。
<!-- XML layout -->
<TextView
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="Very long text that will be truncated"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true" />
<!-- Kotlin code -->
textView.setEllipsize(TextUtils.TruncateAt.MIDDLE)
重要:ellipsize 仅与 maxLines 或 singleLine 组合使用。如果不限制行数,TextView 将在高度上增长,ellipsize 不会激活。从 Android 8.0 (API 26) 开始,ellipsize 支持 maxLines > 1 的多行模式 — 省略号放在最后一行的末尾。
对于编程调用,使用 TextUtils.TruncateAt,值为:END、START、MIDDLE、MARQUEE。NONE 值禁用 ellipsize。
在实践中,END 适用于 90% 的情况 — 用户期望文本在末尾被截断。MIDDLE 用于文件路径(例如 "/User/.../project/main.kt"),以便路径末尾可见。START — 用于具有共同前缀的名称(例如 "...@gmail.com")。
在 iOS 上,ellipsize 的等效项是 UILabel 类的 lineBreakMode 属性(以及 UITextView 的 NSTextContainer)。有三种截断模式可用:.byTruncatingTail(结尾)、.byTruncatingMiddle(中间)和 .byTruncatingHead(开头)。
.byTruncatingTail 模式对应于 android:ellipsize="end"。.byTruncatingHead 模式 — START,.byTruncatingMiddle — MIDDLE。.byClipping 模式 — 截断文本但不显示省略号,在现代界面中很少使用。.byCharWrapping 模式 — 按字符换行而不截断。
let label = UILabel()
label.text = "超出标签边界的长文本"
label.lineBreakMode = .byTruncatingMiddle
label.numberOfLines = 1
// NSAttributedString 也支持 lineBreakMode
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byTruncatingTail
在 iOS 中,截断与 numberOfLines 配合使用。如果 numberOfLines = 1,文本在一行上截断。如果 numberOfLines = 2 — 在第二行上。UITextView 使用 NSTextContainer.lineBreakMode,它也支持所有三种截断模式。
iOS 的特点:UILabel 上的 .byTruncatingMiddle 模式在短行上可能表现异常 — 如果行完全适合,省略号不会出现。为确保短行上显示省略号,请通过 sizeThatFits 使用自定义逻辑。
在 Web 中,ellipsize 通过 CSS 属性 text-overflow: ellipsis 结合 overflow: hidden 和 white-space: nowrap 实现。这是在 Web 界面中使用省略号截断行的标准方法。
.text-cell {
width: 250px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
text-overflow 属性在没 overflow: hidden 的情况下不起作用 — 浏览器需要知道内容被截断。white-space: nowrap 禁止换行,否则文本将转到下一行,不会发生溢出。
对于多行截断(例如,第二行末尾带省略号的 2 行),以前使用实验性属性 -webkit-line-clamp,现在已在 CSS Overflow Level 4 中标准化为 line-clamp。
在实践中,text-overflow: ellipsis 已被所有现代浏览器支持超过 10 年,是 Web 中截断文本最可靠的方法。
选择 ellipsize 模式 会影响 UX,既能改善界面的感知,也可能使用户困惑。主要原则:用户期望截断部分位于最不需要理解的地方。
END 模式适用于标题、标签、名称 — 用户看到行的开头并理解上下文。右侧的省略号表示 “有继续,但没显示下”。这是最直观和最广泛使用的模式。
MIDDLE 模式对于文件路径、电子邮件地址和长标识符必不可少。当行尾包含唯一信息(文件名、域名)时,用户应该看到它,而开头可以缩短。例如:"/User/.../important_document.pdf" — 立即看到文件名。
START 模式很少使用,但对于具有共同前缀的联系人列表很有用 — 例如 "...@gmail.com" 代替 "username@gmail.com",当所有地址属于同一域名时。然而,这种模式更多是令人困惑而不是有帮助。根据 Nielsen Norman Group 的数据,用户从左到右阅读,期望重要信息在开头,因此 START 截断增加了认知负荷。
MARQUEE 模式(滚动文本)仅适用于低更新频率的单行元素:播放器中的当前曲目、新闻滚动条、状态栏。不要在表格、列表或表单中使用 marquee — 动画会分散注意力并降低弱设备的性能。
第一个问题 — ellipsize 不生效。最常见的原因是缺少行数限制。没有 maxLines,TextView 高度增长,不会发生宽度溢出。解决方案:始终指定 maxLines(或 singleLine="true" 用于单行)。
第二个问题 — 编程更改文本时省略号不显示。调用 setText() 后,TextView 可能无法正确重绘。解决方案:更改文本后调用 invalidate() 或 post(() -> requestLayout())。
第三个问题 — 不同 Android 版本上的不同行为。在 API 23 之前,ellipsize 在多行模式 (maxLines > 1) 中不受支持。解决方案:为兼容性检查 Build.VERSION.SDK_INT 并使用 AndroidX 中的 ViewCompat.setEllipsize()。
第四个问题 — 省略号符号在自定义字体中不显示。如果字体不包含 U+2026 字形,省略号将被替换为三个点。解决方案:检查字体是否包含省略号字形,或通过 fontFamily 添加后备字体。
常见问题解答
是的,maxLines 或 singleLine 是必需的。不限制行数,TextView 将高度扩展,截断不会激活。
Ellipsize 在中断位置添加省略号,告知用户存在隐藏文本。Clip 只是简单地在边界处截断文本,没有任何指示符。
标准 text-overflow: ellipsis 在完整单词后截断。要在单词中间截断,请使用 overflow-wrap: break-word 或使用测量宽度的 JavaScript 解决方案。
是的,通过 NSTextContainer 中的 textContainer.lineBreakMode 属性。默认情况下,UITextView 使用 .byWordWrapping;改为 .byTruncatingTail/Middle/Head 进行截断。
调用 textView.setEllipsize(null) 或 textView.setEllipsize(TextUtils.TruncateAt.NONE)。之后文本将换行而不是截断。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。