• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Class (MeasureUtils)
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @hddgzw-->
5<!--Designer: @pssea-->
6<!--Tester: @jiaoaozihao-->
7<!--Adviser: @HelloCrease-->
8
9提供文本宽度、高度等相关计算。
10
11> **说明:**
12>
13> - 本模块首批接口从API version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
14>
15> - 本Class首批接口从API version 12开始支持。
16>
17> - 以下API需先使用UIContext中的[getMeasureUtils()](arkts-apis-uicontext-uicontext.md#getmeasureutils12)方法获取MeasureUtils实例,再通过此实例调用对应方法。
18>
19> - 如需更多测算文本参数,建议使用图形对应测算接口[Paragraph](../apis-arkgraphics2d/js-apis-graphics-text.md#paragraph)接口。
20>
21> - 调用文本计算接口时,不推荐同时用[ApplicationContext.setFontSizeScale](../apis-ability-kit/js-apis-inner-application-applicationContext.md#applicationcontextsetfontsizescale13)设置应用字体大小缩放比例。为了确保时序正确性,建议开发者自行监听字体缩放变化,以保证测算结果的准确性。
22>
23> - 在测算裁剪后的文本时,由于某些Unicode字符(如emoji)的码位长度大于1,直接按字符串长度裁剪会导致不准确的结果。建议基于Unicode码点进行迭代处理,避免错误截断字符,确保测算结果准确。
24
25## measureText<sup>12+</sup>
26
27measureText(options: MeasureOptions): number
28
29计算指定文本单行布局下的宽度。
30
31**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
32
33**系统能力:** SystemCapability.ArkUI.ArkUI.Full
34
35**参数:**
36
37| 参数名     | 类型                              | 必填   | 说明        |
38| ------- | ------------------------------- | ---- | --------- |
39| options | [MeasureOptions](js-apis-measure.md#measureoptions) | 是    | 被计算文本描述信息。 |
40
41**返回值:**
42
43| 类型          | 说明       |
44| ------------  | --------- |
45| number        | 文本宽度。<br/>**说明:**<br/>浮点数会向上取整。<br/>单位:px |
46
47
48**示例:**
49
50通过MeasureUtils的measureText方法获取"Hello World"文字的宽度。
51
52```ts
53import { MeasureUtils } from '@kit.ArkUI';
54
55@Entry
56@Component
57struct Index {
58  @State uiContext: UIContext = this.getUIContext();
59  @State uiContextMeasure: MeasureUtils = this.uiContext.getMeasureUtils();
60  @State textWidth: number = this.uiContextMeasure.measureText({
61    textContent: "Hello World",
62    fontSize: '50px'
63  });
64
65  build() {
66    Row() {
67      Column() {
68        Text(`The width of 'Hello World': ${this.textWidth}`)
69      }
70      .width('100%')
71    }
72    .height('100%')
73  }
74}
75```
76
77## measureTextSize<sup>12+</sup>
78
79measureTextSize(options: MeasureOptions): SizeOptions
80
81计算指定文本单行布局下的宽度和高度。
82
83**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
84
85**系统能力:** SystemCapability.ArkUI.ArkUI.Full
86
87**参数:**
88
89| 参数名     | 类型                              | 必填   | 说明        |
90| ------- | ------------------------------- | ---- | --------- |
91| options | [MeasureOptions](js-apis-measure.md#measureoptions) | 是    | 被计算文本描述信息。 |
92
93**返回值:**
94
95| 类型          | 说明       |
96| ------------  | --------- |
97| [SizeOptions](arkui-ts/ts-types.md#sizeoptions)   | 返回文本所占布局宽度和高度。<br/>**说明:**<br/>没有传参constraintWidth的情况下,文本宽度返回值浮点数会向上取整。<br/>文本宽度以及高度返回值单位均为px。 |
98
99
100**示例:**
101
102通过MeasureUtils的measureTextSize方法获取"Hello World"文字的宽度和高度。
103
104```ts
105import { MeasureUtils } from '@kit.ArkUI';
106
107@Entry
108@Component
109struct Index {
110  @State uiContext: UIContext = this.getUIContext();
111  @State uiContextMeasure: MeasureUtils = this.uiContext.getMeasureUtils();
112  textSize: SizeOptions = this.uiContextMeasure.measureTextSize({
113    textContent: "Hello World",
114    fontSize: '50px'
115  });
116  build() {
117    Row() {
118      Column() {
119        Text(`The width of 'Hello World': ${this.textSize.width}`)
120        Text(`The height of 'Hello World': ${this.textSize.height}`)
121      }
122      .width('100%')
123    }
124    .height('100%')
125  }
126}
127```
128
129
130## getParagraphs<sup>20+</sup>
131
132getParagraphs(styledString: StyledString, options?: TextLayoutOptions): Array\<Paragraph\>
133
134将属性字符串根据文本布局选项转换成对应的[Paragraph](../apis-arkgraphics2d/js-apis-graphics-text.md#paragraph)数组。
135
136**系统能力:** SystemCapability.ArkUI.ArkUI.Full
137
138**参数:**
139
140| 参数名 | 类型   | 必填 | 说明           |
141| ----- | ------ | ---- | -------------- |
142| styledString | [StyledString](arkui-ts/ts-universal-styled-string.md#styledstring) | 是   | 待转换的属性字符串。|
143| options | [TextLayoutOptions](arkui-ts/ts-text-common.md#textlayoutoptions对象说明20) | 否 | 文本布局选项。|
144
145**返回值:**
146
147| 类型     | 说明        |
148| ------ | --------- |
149| Array<[Paragraph](../apis-arkgraphics2d/js-apis-graphics-text.md#paragraph)> | [Paragraph](../apis-arkgraphics2d/js-apis-graphics-text.md#paragraph)的数组。 |
150
151**示例:**
152
153通过MeasureUtils的getParagraphs方法测算文本,当内容超出最大显示行数的时候,截断文本显示并展示“...全文”的效果。
154
155``` typescript
156import { LengthMetrics } from '@kit.ArkUI';
157import { drawing } from '@kit.ArkGraphics2D';
158
159class MyCustomSpan extends CustomSpan {
160  constructor(word: string, width: number, height: number, context: UIContext) {
161    super();
162    this.word = word;
163    this.width = width;
164    this.height = height;
165    this.context = context;
166  }
167
168  onMeasure(measureInfo: CustomSpanMeasureInfo): CustomSpanMetrics {
169    return { width: this.width, height: this.height };
170  }
171
172  onDraw(context: DrawContext, options: CustomSpanDrawInfo) {
173    let canvas = context.canvas;
174    const brush = new drawing.Brush();
175    brush.setColor({
176      alpha: 255,
177      red: 0,
178      green: 74,
179      blue: 175
180    });
181    const font = new drawing.Font();
182    font.setSize(25);
183    const textBlob = drawing.TextBlob.makeFromString(this.word, font, drawing.TextEncoding.TEXT_ENCODING_UTF8);
184    canvas.attachBrush(brush);
185    canvas.drawRect({
186      left: options.x + 10,
187      right: options.x + this.context.vp2px(this.width) - 10,
188      top: options.lineTop + 10,
189      bottom: options.lineBottom - 10
190    });
191    brush.setColor({
192      alpha: 255,
193      red: 23,
194      green: 169,
195      blue: 141
196    });
197    canvas.attachBrush(brush);
198    canvas.drawTextBlob(textBlob, options.x + 20, options.lineBottom - 15);
199    canvas.detachBrush();
200  }
201
202  setWord(word: string) {
203    this.word = word;
204  }
205
206  width: number = 160;
207  word: string = "drawing";
208  height: number = 10;
209  context: UIContext;
210}
211
212@Entry
213@Component
214struct Index {
215  str: string =
216    "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.";
217  mutableStr2 = new MutableStyledString(this.str, [
218    {
219      start: 0,
220      length: 3,
221      styledKey: StyledStringKey.FONT,
222      styledValue: new TextStyle({ fontSize: LengthMetrics.px(20) })
223    },
224    {
225      start: 3,
226      length: 3,
227      styledKey: StyledStringKey.FONT,
228      styledValue: new TextStyle({ fontColor: Color.Brown })
229    }
230  ]);
231
232  // 测算属性字符串在指定宽度下能显示的行数
233  getLineNum(styledString: StyledString, width: LengthMetrics) {
234    let paragraphArr = this.getUIContext().getMeasureUtils().getParagraphs(styledString, { constraintWidth: width });
235    let res = 0;
236    for (let i = 0; i < paragraphArr.length; ++i) {
237      res += paragraphArr[i].getLineCount();
238    }
239    return res;
240  }
241
242  // 测算属性字符串显示maxLines行时最多可以显示的字数
243  getCorrectIndex(styledString: MutableStyledString, maxLines: number, width: LengthMetrics) {
244    let low = 0;
245    let high = styledString.length - 1;
246    // 使用二分查找
247    while (low <= high) {
248      let mid = (low + high) >> 1;
249      console.info("demo: get " + low + " " + high + " " + mid);
250      let moreStyledString = new MutableStyledString("... 全文", [{
251        start: 4,
252        length: 2,
253        styledKey: StyledStringKey.FONT,
254        styledValue: new TextStyle({ fontColor: Color.Blue })
255      }]);
256      moreStyledString.insertStyledString(0, styledString.subStyledString(0, mid));
257      let lineNum = this.getLineNum(moreStyledString, LengthMetrics.px(500));
258      if (lineNum <= maxLines) {
259        low = mid + 1;
260      } else {
261        high = mid - 1;
262      }
263    }
264    return high;
265  }
266
267  mutableStrAllContent = new MutableStyledString(this.str, [
268    {
269      start: 0,
270      length: 3,
271      styledKey: StyledStringKey.FONT,
272      styledValue: new TextStyle({ fontSize: LengthMetrics.px(40) })
273    },
274    {
275      start: 3,
276      length: 3,
277      styledKey: StyledStringKey.FONT,
278      styledValue: new TextStyle({ fontColor: Color.Brown })
279    }
280  ]);
281  customSpan1: MyCustomSpan = new MyCustomSpan("Hello", 120, 10, this.getUIContext());
282  mutableStrAllContent2 = new MutableStyledString(this.str, [
283    {
284      start: 0,
285      length: 3,
286      styledKey: StyledStringKey.FONT,
287      styledValue: new TextStyle({ fontSize: LengthMetrics.px(100) })
288    },
289    {
290      start: 3,
291      length: 3,
292      styledKey: StyledStringKey.FONT,
293      styledValue: new TextStyle({ fontColor: Color.Brown })
294    }
295  ]);
296  controller: TextController = new TextController();
297  controller2: TextController = new TextController();
298  textController: TextController = new TextController();
299  textController2: TextController = new TextController();
300
301  aboutToAppear() {
302    this.mutableStrAllContent2.insertStyledString(0, new StyledString(this.customSpan1));
303    this.mutableStr2.insertStyledString(0, new StyledString(this.customSpan1));
304  }
305
306  build() {
307    Scroll() {
308      Column() {
309        Text('原文')
310        Text(undefined, { controller: this.controller }).width('500px').onAppear(() => {
311          this.controller.setStyledString(this.mutableStrAllContent);
312        })
313        Divider().strokeWidth(8).color('#F1F3F5')
314        Text('排版后')
315        Text(undefined, { controller: this.textController }).onAppear(() => {
316          let now = this.getCorrectIndex(this.mutableStrAllContent, 3, LengthMetrics.px(500));
317          if (now != this.mutableStrAllContent.length - 1) {
318            let moreStyledString = new MutableStyledString("... 全文", [{
319              start: 4,
320              length: 2,
321              styledKey: StyledStringKey.FONT,
322              styledValue: new TextStyle({ fontColor: Color.Blue })
323            }]);
324            moreStyledString.insertStyledString(0, this.mutableStrAllContent.subStyledString(0, now));
325            this.textController.setStyledString(moreStyledString);
326          } else {
327            this.textController.setStyledString(this.mutableStrAllContent);
328          }
329        })
330          .width('500px')
331        Divider().strokeWidth(8).color('#F1F3F5')
332        Text('原文')
333        Text(undefined, { controller: this.controller2 }).width('500px').onAppear(() => {
334          this.controller2.setStyledString(this.mutableStrAllContent2);
335        })
336        Divider().strokeWidth(8).color('#F1F3F5')
337        Text('排版后')
338        Text(undefined, { controller: this.textController2 }).onAppear(() => {
339          let now = this.getCorrectIndex(this.mutableStrAllContent2, 3, LengthMetrics.px(500));
340          let moreStyledString = new MutableStyledString("... 全文", [{
341            start: 4,
342            length: 2,
343            styledKey: StyledStringKey.FONT,
344            styledValue: new TextStyle({ fontColor: Color.Blue })
345          }]);
346          moreStyledString.insertStyledString(0, this.mutableStrAllContent2.subStyledString(0, now));
347          this.textController2.setStyledString(moreStyledString);
348        })
349          .width('500px')
350      }.width('100%')
351    }
352  }
353}
354```
355![](figures/styledString_15.png)
356