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 356