本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
鸿蒙(HarmonyOS)开发中,实现文本的展开与折叠功能是常见的交互,尤其在新闻、评论等场景中。以下是详细的实现方案,涵盖 基础实现、动画效果、 及 代码示例。
一、基础实现:文本截断与展开
1. 核心API与属性
API/属性 | 作用 | 类型 |
---|---|---|
maxLines | 控制文本最大行数 | number |
textOverflow | 超出部分显示方式(如ellipsis ) | {overflow: TextOverflow} |
onClick | 点击事件绑定 | () => void |
2. 基础实现代码
@Entry
@Component
struct ExpandableText {
@State isExpanded: boolean = false; // 控制展开状态
@State fullText: string = '这是一段需要展开的长文本...'.repeat(10); // 长文本
build() {
Column() {
// 文本部分:根据状态切换行数
Text(this.fullText)
.maxLines(this.isExpanded ? undefined : 3) // 折叠时显示3行
.textOverflow({ overflow: TextOverflow.Ellipsis }) // 超出显示省略号
.fontSize(16)
.margin(10)
// 展开/折叠按钮
Button(this.isExpanded ? '收起' : '展开全文')
.onClick(() => {
this.isExpanded = !this.isExpanded; // 切换状态
})
.margin({ top: 5 })
}
}
}
二、高级功能扩展
1. 动画效果(平滑展开)
使用 animateTo
实现过渡动画:
import { animateTo } from '@ohos.animator';
@State textHeight: number = 60; // 初始高度(3行文本高度)
build() {
Column() {
Text(this.fullText)
.height(this.textHeight) // 绑定动态高度
.textOverflow({ overflow: TextOverflow.Ellipsis })
Button(this.isExpanded ? '收起' : '展开全文')
.onClick(() => {
animateTo({
duration: 300, // 动画时长300ms
curve: Curve.EaseOut
}, () => {
this.textHeight = this.isExpanded ? 60 : 200; // 切换目标高度
this.isExpanded = !this.isExpanded;
});
})
}
}
2. 动态计算文本高度
通过 TextMetrics
获取文本实际高度:
import { TextMetrics } from '@ohos.text';
@State textHeight: number = 0;
aboutToAppear() {
const metrics = TextMetrics.measureText({
text: this.fullText,
fontSize: 16,
maxWidth: '100%',
maxLines: 3 // 折叠时的行数
});
this.textHeight = metrics.height;
}
三、优化方案
1. 文本分页加载
适用于超长文本(如小说):
@State visibleText: string = '';
@State pageSize: number = 500; // 每次加载500字符
loadMoreText() {
this.visibleText = this.fullText.substring(0, this.visibleText.length + this.pageSize);
}
build() {
Column() {
Text(this.visibleText)
Button('加载更多')
.onClick(() => this.loadMoreText())
}
}
2. 复用文本测量结果
缓存 TextMetrics
计算结果,避免重复测量:
private cachedHeight: number | null = null;
getTextHeight() {
if (this.cachedHeight === null) {
const metrics = TextMetrics.measureText({ /* ... */ });
this.cachedHeight = metrics.height;
}
return this.cachedHeight;
}
四、完整案例:带动画的展开折叠
@Entry
@Component
struct AdvancedExpandableText {
@State isExpanded: boolean = false;
@State textHeight: number = 80; // 初始高度(约3行)
@State fullText: string = '长文本内容...'.repeat(50);
// 计算文本高度
calcHeight() {
const metrics = TextMetrics.measureText({
text: this.fullText,
fontSize: 16,
maxWidth: '80%',
maxLines: this.isExpanded ? undefined : 3
});
this.textHeight = metrics.height;
}
build() {
Column() {
// 文本容器(带动画高度)
Stack() {
Text(this.fullText)
.fontSize(16)
.width('80%')
.height(this.textHeight)
.textOverflow({ overflow: TextOverflow.Ellipsis })
// 渐变遮罩(折叠时显示)
if (!this.isExpanded) {
Gradient()
.colors(['#FFFFFF00', '#FFFFFFFF'])
.height(30)
.width('100%')
.align(Alignment.Bottom)
}
}
.margin(10)
// 展开/折叠按钮
Button(this.isExpanded ? $r('app.string.collapse') : $r('app.string.expand'))
.onClick(() => {
animateTo({
duration: 300,
curve: Curve.EaseInOut
}, () => {
this.isExpanded = !this.isExpanded;
this.calcHeight(); // 重新计算高度
});
})
.backgroundColor('#FFFFFF')
.borderColor('#007DFF')
}
}
}
五、常见问题
问题 | 原因 | 解决方案 |
---|---|---|
文本高度计算不准 | 字体/间距未统一 | 确保测量时与渲染样式一致 |
动画卡顿 | 文本过长或设备性能差 | 分页加载或减少动画复杂度 |
省略号不显示 | maxLines 未设置 | 检查maxLines 和textOverflow |
六、建议
-
设计规范
- 折叠时保留 2-3行 文本,避免过度截断。
- 按钮文案明确(如“展开全文”而非“更多”)。