鸿蒙 HarmonyOS NEXT 自定义文本测量实现
- 作者: 刘杰
- 来源: 技术那些事
- 阅读:200
- 发布: 2025-06-30 09:46
- 最后更新: 2025-07-06 09:48
自定义文本测量工具
以下是个人实现的一段文本测量的函数。代码是基于 HarmonyOS NEXT 实现的,用于获取显示满指定的文本组件,所需要的文本字符数。一般用在什么需求里呢,比如一章节小说,大概几千字,根据字号不同,可能需要二十甚至三十多页才能到下一章,在仿真翻页的情况下,一屏是固定大小的,就需要知道到底需要多少屏才能将所有文本存放。
typescript
/**
* 获取显示满指定文本组件所需要的文本字符数.
* @param utils 文本测量工具对象
* @param options 文本测量选项(需要跟目标 Text 组件的配置一致)
* @param totalWidth 文本组件显示区域的宽度.
* @param totalHeight 文本组件目标显示区域的高度.
* @returns 铺满文本组件所需要的字符数.
*/
static subStringMeasure(utils: MeasureUtils, options: MeasureOptions, totalWidth: number, totalHeight: Length): number {
// 获取单行的行高
options.maxLines = 1;
let size: SizeOptions = utils.measureTextSize(options);
// 行高和总高不存在则无法计算.
if (!totalHeight || !size.height) {
return 0;
}
// 计算需要的行数.
let lineNum = Math.floor(totalHeight as number / (size.height as number));
// 每行最多放的字符数(全为半角字符,且无其他字符间距之类的调整)
if (!options.fontSize) {
options.fontSize = '16fp';
}
// 计算一行最多需要多少个半角字符.
let charPerLine = Math.floor(totalWidth / (options.fontSize as number) / 2);
// 估算需要总的文本数量.
let totalTextLength = charPerLine * lineNum;
// 截取估算的文本数.
let originText = options.textContent;
options.textContent = originText.toString().substring(0, totalTextLength);
// 最大行高为目标行的二倍
options.maxLines = lineNum * 2;
// 从最多的字符数开始依次递减
let readyToBreak = false; // 一旦为 true,且 tmpLen不为 0 时说明已经匹配到.
// 超出 100 结束匹配.
let limit: number = 0;
for (; limit < 100; ++limit) {
// 计算当前的文本高度与目标文本高度的差所代表的行(最后一行不算,需要多算一行).
let tmpLen = Math.floor(((utils.measureTextSize(options).height as number) - (totalHeight as number)) / (size.height as number) + 1);
// 表示当前的文字正好达到指定高度最后一行.
if (tmpLen === 0) {
readyToBreak = true;
// 行数一致,字符数需要填满最后一行.
totalTextLength += 1;
} else {
if (readyToBreak) {
// 如果已经匹配过,目前又不匹配,那么之前的匹配正好是一屏.
totalTextLength -= 1;
break;
}
// 表示文本过少,需要增加,每次增加(tmpLen * charPerLine/2)的数量.
totalTextLength -= Math.floor(charPerLine / 2 * tmpLen);
}
options.textContent = originText.toString().substring(0, totalTextLength);
}
// 打印匹配到目标高度的次数.
// console.log('measure text times: ' + limit);
return totalTextLength;
}