HarmonyOS 鸿蒙Next中文本展开折叠:从纯文本到富文本的完整解决方案

HarmonyOS 鸿蒙Next中文本展开折叠:从纯文本到富文本的完整解决方案 在内容类应用中,处理长文本的展示与交互是高频需求。如何在有限空间内优雅地呈现内容,并提供流畅的展开/收起体验?本文将从笔者自身经验触发,从纯文本到富文本,和大家聊聊从我在HarmonyOS中的实现方案。

cke_27059.jpeg

一、 纯文本展开折叠:精准计算的简洁之道

场景需求

  • 纯文本内容超过2行时显示"…展开"
  • 点击后展示全文,并显示"收起"按钮
  • 需要精确计算截断位置

cke_29870.jpeg

实现原理

cke_31702.jpeg

通过文本测量API计算出恰好显示指定行数的文本内容,使用二分法高效定位截断点。

核心代码实现

// 判断是否需要展开折叠功能
getIsExpanded() {
  // 测量完整文本高度
  let titleSize: SizeOptions = this.uiContext.getMeasureUtils().measureTextSize({
    textContent: this.textSectionAttribute.title,
    lineHeight: this.textSectionAttribute.lineHeight,
    constraintWidth: this.textSectionAttribute.constraintWidth,
    fontSize: this.textSectionAttribute.fontSize
  });
  
  let height = this.getUIContext().px2vp(Number(titleSize.height));
  
  // 判断是否超过2行
  if (height <= this.textSectionAttribute.lineHeight * 2) {
    this.textModifier.needProcess = false;
    this.textModifier.title = this.textSectionAttribute.title;
    return;
  } else {
    this.textModifier.needProcess = true;
  }
  
  // 根据展开状态处理文本
  if (this.expanded) {
    this.collapseText();
  } else {
    this.expandText();
  }
}

// 使用二分法精确查找截断位置
public static getShortText(textSectionAttribute: TextSectionAttribute, lastSpan: string): string {
  let text = TextUtils.getStringFromResource(textSectionAttribute.title);
  const minLinesTextSize: SizeOptions | undefined = uiContext?.getMeasureUtils().measureTextSize({
    textContent: text,
    fontSize: textSectionAttribute.fontSize,
    maxLines: textSectionAttribute.maxLines,
    wordBreak: WordBreak.BREAK_ALL,
    constraintWidth: textSectionAttribute.constraintWidth
  });
  
  const minHeight: Length | undefined = minLinesTextSize?.height;
  if (minHeight === undefined) return '';

  let textStr: string[] = Array.from(text);
  let leftCursor: number = 0;
  let rightCursor: number = textStr.length;
  let cursor: number = Math.floor(rightCursor / 2);
  
  // 二分查找最优截断点
  while (Math.abs(rightCursor - leftCursor) > 1) {
    let tempTitle = text.substring(0, cursor) + suffix + lastSpan;
    const currentLinesTextSize = uiContext?.getMeasureUtils().measureTextSize({
      textContent: tempTitle,
      fontSize: textSectionAttribute.fontSize,
      wordBreak: WordBreak.BREAK_ALL,
      constraintWidth: textSectionAttribute.constraintWidth
    });
    
    if (currentLinesTextSize?.height > minHeight) {
      rightCursor = cursor;  // 超过行高,向左查找
    } else {
      leftCursor = cursor;   // 未超过行高,向右查找
    }
    cursor = leftCursor + Math.floor((rightCursor - leftCursor) / 2);
  }
  
  return text.substring(0, cursor) + suffix;
}

二、 富文本展开折叠:复杂内容的高级处理

场景挑战

  • 文本中包含表情图片、不同颜色字号
  • 关键字带有超链接功能
  • 图片位置和大小不固定,截断计算复杂

cke_33617.jpeg

实现原理

利用HarmonyOS的graphics.text模块进行精确的文本排版计算,通过坐标转换确定截断位置。

核心实现步骤

1. 初始化文本排版环境

// 创建段落样式
let myParagraphStyle: text.ParagraphStyle = {
  textStyle: {
    fontSize: uiContext?.fp2px(fontSize)  // 注意单位转换
  },
  align: text.TextAlign.START,
  maxLines: 300,  // 设置足够大的行数进行预排版
  breakStrategy: text.BreakStrategy.GREEDY,
  wordBreak: text.WordBreak.BREAK_WORD
};

let fontCollection = new text.FontCollection();
let paragraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);

2. 混合处理文本和图片

// 遍历富文本内容
for (let item of textArray) {
  if (item.type === 'image') {
    // 添加图片占位符
    paragraphGraphBuilder.addPlaceholder({
      width: item.imgWidth,
      height: item.imgHeight,
      align: text.PlaceholderAlignment.BOTTOM_OF_ROW_BOX,
      baseline: text.TextBaseline.IDEOGRAPHIC,
      baselineOffset: 0
    });
  } else if (item.type === 'text') {
    // 设置文本样式
    paragraphGraphBuilder.pushStyle({
      fontSize: fontSize,
      color: item.color  // 支持不同颜色
    });
    paragraphGraphBuilder.addText(item.content);
    paragraphGraphBuilder.popStyle();  // 恢复默认样式
  }
}

3. 预排版与截断计算

// 执行排版计算
let paragraph = paragraphGraphBuilder.build();
paragraph.layoutSync(textMaxWidth);  // 与实际显示宽度一致

// 计算截断位置的Y坐标
let y = 0;
for (let i = 0; i < textSectionAttribute.maxLines; i++) {
  y += (i === textSectionAttribute.maxLines - 1) ? 
       paragraph.getLineHeight(i) / 2 : paragraph.getLineHeight(i);
}

// 计算截断位置的X坐标
let x = 0;
if (paragraph.getLineWidth(textSectionAttribute.maxLines - 1) + Number(widthMore) > textSectionAttribute.constraintWidth) {
  x = textSectionAttribute.constraintWidth - Number(widthMore);
} else {
  x = paragraph.getLineWidth(textSectionAttribute.maxLines - 1);
}

// 坐标转换为文本索引
let positionWithAffinity = paragraph.getGlyphPositionAtCoordinate(x, y);
let index = (positionWithAffinity.affinity === text.Affinity.UPSTREAM) ? 
            positionWithAffinity.position : positionWithAffinity.position + 1;

4. 动态按钮渲染

// 根据状态显示不同按钮
if (this.textModifier.needProcess && !this.textModifier.exceedOneLine) {
  // 显示"展开"按钮
  Span(this.lastSpanAttribute.content[0])
    .fontColor(this.lastSpanAttribute.color)
    .onClick(() => {
      this.expanded = true;
      this.expandText();
    })
} else if (this.textModifier.exceedOneLine) {
  // 显示"收起"按钮
  Span(this.lastSpanAttribute.content[1])
    .fontColor(this.lastSpanAttribute.color)
    .onClick(() => {
      this.expanded = false;
      this.collapseText();
    })
}

三、 关键技术要点

1. 单位转换一致性

  • 排版计算使用px单位
  • 显示时进行px2vp转换
  • 字体大小考虑系统缩放比例

2. 性能优化策略

  • 二分法查找避免全量计算
  • 预排版只执行一次
  • 缓存计算结果减少重复测量

3. 兼容性处理

  • 纯文本降级方案
  • 富文本图片容错
  • 多语言字符支持

四、 总结

HarmonyOS提供了从简单到复杂的完整文本处理方案:

  • 纯文本场景:使用measureTextSizeAPI快速实现,代码简洁高效
  • 富文本场景:借助graphics.text排版引擎,精准处理混合内容

两种方案都通过精确的数学计算确保截断位置的准确性,为用户提供流畅自然的展开收起体验。开发者可以根据业务复杂度选择合适的实现路径,构建体验优秀的文本展示组件。

这套方案已在实际项目中验证,能够稳定处理各种复杂的文本场景,是构建内容类应用的理想选择。

班级链接:https://developer.huawei.com/consumer/cn/training/classDetail/9d5d34e77df44f55bb7d2bd83ed8dd94?type=1?ha_source=hmosclass&ha_sourceId=89000248


更多关于HarmonyOS 鸿蒙Next中文本展开折叠:从纯文本到富文本的完整解决方案的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

666

更多关于HarmonyOS 鸿蒙Next中文本展开折叠:从纯文本到富文本的完整解决方案的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,文本展开折叠功能通过Text组件结合自定义布局实现。使用文本插值和条件渲染控制显示内容长度,通过状态变量管理展开/折叠状态。富文本支持通过Span组件添加样式和交互,结合Click事件处理展开折叠逻辑。布局自动适配文本内容变化,确保UI流畅性。系统提供文本测量接口精确计算截断位置,避免字符截断问题。

这篇文章详细介绍了HarmonyOS Next中文本展开折叠功能的完整实现方案,技术深度和实用性都很强。

纯文本部分通过measureTextSizeAPI结合二分法精确计算截断位置,代码简洁高效。富文本处理则充分利用了graphics.text排版引擎,通过坐标转换处理混合内容,解决了图片、不同样式等复杂场景的截断难题。

特别值得肯定的是文中提到的关键技术要点:单位转换一致性、性能优化策略和兼容性处理,这些都是实际开发中容易忽略但至关重要的细节。二分法查找和预排版缓存的优化策略能有效提升性能表现。

这套方案从简单到复杂覆盖了完整的应用场景,为HarmonyOS开发者提供了很好的参考实现。

回到顶部