# Class (MeasureUtils)
提供文本宽度、高度等相关计算。
> **说明:**
>
> - 本模块首批接口从API version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
>
> - 本Class首批接口从API version 12开始支持。
>
> - 以下API需先使用UIContext中的[getMeasureUtils()](arkts-apis-uicontext-uicontext.md#getmeasureutils12)方法获取MeasureUtils实例,再通过此实例调用对应方法。
>
> - 如需更多测算文本参数,建议使用图形对应测算接口[Paragraph](../apis-arkgraphics2d/js-apis-graphics-text.md#paragraph)接口。
>
> - 调用文本计算接口时,不推荐同时用[ApplicationContext.setFontSizeScale](../apis-ability-kit/js-apis-inner-application-applicationContext.md#applicationcontextsetfontsizescale13)设置应用字体大小缩放比例。为了确保时序正确性,建议开发者自行监听字体缩放变化,以保证测算结果的准确性。
>
> - 在测算裁剪后的文本时,由于某些Unicode字符(如emoji)的码位长度大于1,直接按字符串长度裁剪会导致不准确的结果。建议基于Unicode码点进行迭代处理,避免错误截断字符,确保测算结果准确。
## measureText12+
measureText(options: MeasureOptions): number
计算指定文本单行布局下的宽度。
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ------- | ------------------------------- | ---- | --------- |
| options | [MeasureOptions](js-apis-measure.md#measureoptions) | 是 | 被计算文本描述信息。 |
**返回值:**
| 类型 | 说明 |
| ------------ | --------- |
| number | 文本宽度。
**说明:**
浮点数会向上取整。
单位:px |
**示例:**
通过MeasureUtils的measureText方法获取"Hello World"文字的宽度。
```ts
import { MeasureUtils } from '@kit.ArkUI';
@Entry
@Component
struct Index {
@State uiContext: UIContext = this.getUIContext();
@State uiContextMeasure: MeasureUtils = this.uiContext.getMeasureUtils();
@State textWidth: number = this.uiContextMeasure.measureText({
textContent: "Hello World",
fontSize: '50px'
});
build() {
Row() {
Column() {
Text(`The width of 'Hello World': ${this.textWidth}`)
}
.width('100%')
}
.height('100%')
}
}
```
## measureTextSize12+
measureTextSize(options: MeasureOptions): SizeOptions
计算指定文本单行布局下的宽度和高度。
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ------- | ------------------------------- | ---- | --------- |
| options | [MeasureOptions](js-apis-measure.md#measureoptions) | 是 | 被计算文本描述信息。 |
**返回值:**
| 类型 | 说明 |
| ------------ | --------- |
| [SizeOptions](arkui-ts/ts-types.md#sizeoptions) | 返回文本所占布局宽度和高度。
**说明:**
没有传参constraintWidth的情况下,文本宽度返回值浮点数会向上取整。
文本宽度以及高度返回值单位均为px。 |
**示例:**
通过MeasureUtils的measureTextSize方法获取"Hello World"文字的宽度和高度。
```ts
import { MeasureUtils } from '@kit.ArkUI';
@Entry
@Component
struct Index {
@State uiContext: UIContext = this.getUIContext();
@State uiContextMeasure: MeasureUtils = this.uiContext.getMeasureUtils();
textSize: SizeOptions = this.uiContextMeasure.measureTextSize({
textContent: "Hello World",
fontSize: '50px'
});
build() {
Row() {
Column() {
Text(`The width of 'Hello World': ${this.textSize.width}`)
Text(`The height of 'Hello World': ${this.textSize.height}`)
}
.width('100%')
}
.height('100%')
}
}
```
## getParagraphs20+
getParagraphs(styledString: StyledString, options?: TextLayoutOptions): Array\
将属性字符串根据文本布局选项转换成对应的[Paragraph](../apis-arkgraphics2d/js-apis-graphics-text.md#paragraph)数组。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ----- | ------ | ---- | -------------- |
| styledString | [StyledString](arkui-ts/ts-universal-styled-string.md#styledstring) | 是 | 待转换的属性字符串。|
| options | [TextLayoutOptions](arkui-ts/ts-text-common.md#textlayoutoptions对象说明20) | 否 | 文本布局选项。|
**返回值:**
| 类型 | 说明 |
| ------ | --------- |
| Array<[Paragraph](../apis-arkgraphics2d/js-apis-graphics-text.md#paragraph)> | [Paragraph](../apis-arkgraphics2d/js-apis-graphics-text.md#paragraph)的数组。 |
**示例:**
通过MeasureUtils的getParagraphs方法测算文本,当内容超出最大显示行数的时候,截断文本显示并展示“...全文”的效果。
``` typescript
import { LengthMetrics } from '@kit.ArkUI';
import { drawing } from '@kit.ArkGraphics2D';
class MyCustomSpan extends CustomSpan {
constructor(word: string, width: number, height: number, context: UIContext) {
super();
this.word = word;
this.width = width;
this.height = height;
this.context = context;
}
onMeasure(measureInfo: CustomSpanMeasureInfo): CustomSpanMetrics {
return { width: this.width, height: this.height };
}
onDraw(context: DrawContext, options: CustomSpanDrawInfo) {
let canvas = context.canvas;
const brush = new drawing.Brush();
brush.setColor({
alpha: 255,
red: 0,
green: 74,
blue: 175
});
const font = new drawing.Font();
font.setSize(25);
const textBlob = drawing.TextBlob.makeFromString(this.word, font, drawing.TextEncoding.TEXT_ENCODING_UTF8);
canvas.attachBrush(brush);
canvas.drawRect({
left: options.x + 10,
right: options.x + this.context.vp2px(this.width) - 10,
top: options.lineTop + 10,
bottom: options.lineBottom - 10
});
brush.setColor({
alpha: 255,
red: 23,
green: 169,
blue: 141
});
canvas.attachBrush(brush);
canvas.drawTextBlob(textBlob, options.x + 20, options.lineBottom - 15);
canvas.detachBrush();
}
setWord(word: string) {
this.word = word;
}
width: number = 160;
word: string = "drawing";
height: number = 10;
context: UIContext;
}
@Entry
@Component
struct Index {
str: string =
"Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.";
mutableStr2 = new MutableStyledString(this.str, [
{
start: 0,
length: 3,
styledKey: StyledStringKey.FONT,
styledValue: new TextStyle({ fontSize: LengthMetrics.px(20) })
},
{
start: 3,
length: 3,
styledKey: StyledStringKey.FONT,
styledValue: new TextStyle({ fontColor: Color.Brown })
}
]);
// 测算属性字符串在指定宽度下能显示的行数
getLineNum(styledString: StyledString, width: LengthMetrics) {
let paragraphArr = this.getUIContext().getMeasureUtils().getParagraphs(styledString, { constraintWidth: width });
let res = 0;
for (let i = 0; i < paragraphArr.length; ++i) {
res += paragraphArr[i].getLineCount();
}
return res;
}
// 测算属性字符串显示maxLines行时最多可以显示的字数
getCorrectIndex(styledString: MutableStyledString, maxLines: number, width: LengthMetrics) {
let low = 0;
let high = styledString.length - 1;
// 使用二分查找
while (low <= high) {
let mid = (low + high) >> 1;
console.info("demo: get " + low + " " + high + " " + mid);
let moreStyledString = new MutableStyledString("... 全文", [{
start: 4,
length: 2,
styledKey: StyledStringKey.FONT,
styledValue: new TextStyle({ fontColor: Color.Blue })
}]);
moreStyledString.insertStyledString(0, styledString.subStyledString(0, mid));
let lineNum = this.getLineNum(moreStyledString, LengthMetrics.px(500));
if (lineNum <= maxLines) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return high;
}
mutableStrAllContent = new MutableStyledString(this.str, [
{
start: 0,
length: 3,
styledKey: StyledStringKey.FONT,
styledValue: new TextStyle({ fontSize: LengthMetrics.px(40) })
},
{
start: 3,
length: 3,
styledKey: StyledStringKey.FONT,
styledValue: new TextStyle({ fontColor: Color.Brown })
}
]);
customSpan1: MyCustomSpan = new MyCustomSpan("Hello", 120, 10, this.getUIContext());
mutableStrAllContent2 = new MutableStyledString(this.str, [
{
start: 0,
length: 3,
styledKey: StyledStringKey.FONT,
styledValue: new TextStyle({ fontSize: LengthMetrics.px(100) })
},
{
start: 3,
length: 3,
styledKey: StyledStringKey.FONT,
styledValue: new TextStyle({ fontColor: Color.Brown })
}
]);
controller: TextController = new TextController();
controller2: TextController = new TextController();
textController: TextController = new TextController();
textController2: TextController = new TextController();
aboutToAppear() {
this.mutableStrAllContent2.insertStyledString(0, new StyledString(this.customSpan1));
this.mutableStr2.insertStyledString(0, new StyledString(this.customSpan1));
}
build() {
Scroll() {
Column() {
Text('原文')
Text(undefined, { controller: this.controller }).width('500px').onAppear(() => {
this.controller.setStyledString(this.mutableStrAllContent);
})
Divider().strokeWidth(8).color('#F1F3F5')
Text('排版后')
Text(undefined, { controller: this.textController }).onAppear(() => {
let now = this.getCorrectIndex(this.mutableStrAllContent, 3, LengthMetrics.px(500));
if (now != this.mutableStrAllContent.length - 1) {
let moreStyledString = new MutableStyledString("... 全文", [{
start: 4,
length: 2,
styledKey: StyledStringKey.FONT,
styledValue: new TextStyle({ fontColor: Color.Blue })
}]);
moreStyledString.insertStyledString(0, this.mutableStrAllContent.subStyledString(0, now));
this.textController.setStyledString(moreStyledString);
} else {
this.textController.setStyledString(this.mutableStrAllContent);
}
})
.width('500px')
Divider().strokeWidth(8).color('#F1F3F5')
Text('原文')
Text(undefined, { controller: this.controller2 }).width('500px').onAppear(() => {
this.controller2.setStyledString(this.mutableStrAllContent2);
})
Divider().strokeWidth(8).color('#F1F3F5')
Text('排版后')
Text(undefined, { controller: this.textController2 }).onAppear(() => {
let now = this.getCorrectIndex(this.mutableStrAllContent2, 3, LengthMetrics.px(500));
let moreStyledString = new MutableStyledString("... 全文", [{
start: 4,
length: 2,
styledKey: StyledStringKey.FONT,
styledValue: new TextStyle({ fontColor: Color.Blue })
}]);
moreStyledString.insertStyledString(0, this.mutableStrAllContent2.subStyledString(0, now));
this.textController2.setStyledString(moreStyledString);
})
.width('500px')
}.width('100%')
}
}
}
```
