1# 文本显示 (Text/Span) 2<!--Kit: ArkUI--> 3<!--Subsystem: ArkUI--> 4<!--Owner: @xiangyuan6--> 5<!--Designer: @pssea--> 6<!--Tester: @jiaoaozihao--> 7<!--Adviser: @HelloCrease--> 8 9 10Text是文本组件,用于展示用户视图,如显示文章的文字内容。该组件支持绑定自定义文本选择菜单,用户可根据需要选择不同功能。此外,还可以扩展自定义菜单,丰富可用选项,进一步提升用户体验。Span则用于展示行内文本。 11 12具体用法请参考[Text](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md)和[Span](../reference/apis-arkui/arkui-ts/ts-basic-components-span.md)组件的使用说明。 13 14 15## 创建文本 16 17Text可通过以下两种方式来创建: 18 19 20- string字符串。 21 22 ```ts 23 Text('我是一段文本') 24 ``` 25 26 27 28 29 30- 引用Resource资源。 31 32 资源引用类型可以通过$r创建Resource类型对象,文件位置为/resources/base/element/string.json,具体内容如下: 33 34 ```json 35 { 36 "string": [ 37 { 38 "name": "module_desc", 39 "value": "模块描述" 40 } 41 ] 42 } 43 ``` 44 45 ```ts 46 Text($r('app.string.module_desc')) 47 .baselineOffset(0) 48 .fontSize(30) 49 .border({ width: 1 }) 50 .padding(10) 51 .width(300) 52 ``` 53 54  55 56 57## 添加子组件 58 59[Span](../reference/apis-arkui/arkui-ts/ts-basic-components-span.md)只能作为[Text](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md)和[RichEditor](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md)组件的子组件显示文本内容。可以在一个Text内添加多个Span来显示一段信息,例如产品说明书、承诺书等。 60 61- 创建Span。 62 63 Span组件需嵌入在Text组件中才能显示,单独使用时不会显示任何内容。Text与Span同时配置文本内容时,Span内容将覆盖Text内容。 64 65 66 ```ts 67 Text('我是Text') { 68 Span('我是Span') 69 } 70 .padding(10) 71 .borderWidth(1) 72 ``` 73 74  75 76- 设置文本装饰线及颜色。 77 78 通过[decoration](../reference/apis-arkui/arkui-ts/ts-basic-components-span.md#decoration)设置文本装饰线及颜色。 79 80 81 ```ts 82 Text() { 83 Span('我是Span1,').fontSize(16).fontColor(Color.Grey) 84 .decoration({ type: TextDecorationType.LineThrough, color: Color.Red }) 85 Span('我是Span2').fontColor(Color.Blue).fontSize(16) 86 .fontStyle(FontStyle.Italic) 87 .decoration({ type: TextDecorationType.Underline, color: Color.Black }) 88 Span(',我是Span3').fontSize(16).fontColor(Color.Grey) 89 .decoration({ type: TextDecorationType.Overline, color: Color.Green }) 90 } 91 .borderWidth(1) 92 .padding(10) 93 ``` 94 95  96 97- 通过[textCase](../reference/apis-arkui/arkui-ts/ts-basic-components-span.md#textcase)设置文字一直保持大写或者小写状态。 98 99 ```ts 100 Text() { 101 Span('I am Upper-span').fontSize(12) 102 .textCase(TextCase.UpperCase) 103 } 104 .borderWidth(1) 105 .padding(10) 106 ``` 107 108  109 110- 添加事件。 111 112 由于Span组件无尺寸信息,仅支持添加点击事件[onClick](../reference/apis-arkui/arkui-ts/ts-universal-events-click.md#onclick)、悬浮事件[onHover](../reference/apis-arkui/arkui-ts/ts-universal-events-hover.md#onhover)。 113 114 115 ```ts 116 // xxx.ets 117 @Entry 118 @Component 119 struct Index { 120 @State textStr1: string = ''; 121 @State textStr2: string = ''; 122 123 build() { 124 Row() { 125 Column() { 126 Text() { 127 Span('I am Upper-span') 128 .textCase(TextCase.UpperCase) 129 .fontSize(30) 130 .onClick(() => { 131 console.info('Span onClick is triggering'); 132 this.textStr1 = 'Span onClick is triggering'; 133 }) 134 .onHover(() => { 135 console.info('Span onHover is triggering'); 136 this.textStr2 = 'Span onHover is triggering'; 137 }) 138 } 139 140 Text('onClick:' + this.textStr1) 141 .fontSize(20) 142 Text('onHover:' + this.textStr2) 143 .fontSize(20) 144 }.width('100%') 145 } 146 .height('100%') 147 } 148 } 149 ``` 150 151  152 153## 创建自定义文本样式 154 155- 通过[textAlign](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#textalign)属性设置文本对齐样式。 156 157 ```ts 158 Text('左对齐') 159 .width(300) 160 .textAlign(TextAlign.Start) 161 .border({ width: 1 }) 162 .padding(10) 163 Text('中间对齐') 164 .width(300) 165 .textAlign(TextAlign.Center) 166 .border({ width: 1 }) 167 .padding(10) 168 Text('右对齐') 169 .width(300) 170 .textAlign(TextAlign.End) 171 .border({ width: 1 }) 172 .padding(10) 173 ``` 174 175  176 177- 通过[textOverflow](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#textoverflow)属性控制文本超长处理,textOverflow需配合[maxLines](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#maxlines)一起使用(默认情况下文本自动折行)。从API version 18开始,文本超长时设置跑马灯的方式展示时,支持设置跑马灯的配置项,比如开关、步长、循环次数、方向等。 178 179 ```ts 180 Text('This is the setting of textOverflow to Clip text content This is the setting of textOverflow to None text content. This is the setting of textOverflow to Clip text content This is the setting of textOverflow to None text content.') 181 .width(250) 182 .textOverflow({ overflow: TextOverflow.None }) 183 .maxLines(1) 184 .fontSize(12) 185 .border({ width: 1 }) 186 .padding(10) 187 Text('我是超长文本,超出的部分显示省略号。I am an extra long text, with ellipses displayed for any excess.') 188 .width(250) 189 .textOverflow({ overflow: TextOverflow.Ellipsis }) 190 .maxLines(1) 191 .fontSize(12) 192 .border({ width: 1 }) 193 .padding(10) 194 Text('当文本溢出其尺寸时,文本将滚动显示。When the text overflows its dimensions, the text will scroll for displaying.') 195 .width(250) 196 .textOverflow({ overflow: TextOverflow.MARQUEE }) 197 .maxLines(1) 198 .fontSize(12) 199 .border({ width: 1 }) 200 .padding(10) 201 Text('当文本溢出其尺寸时,文本将滚动显示,支持设置跑马灯配置项。When the text overflows its dimensions, the text will scroll for displaying.') 202 .width(250) 203 .textOverflow({ overflow: TextOverflow.MARQUEE }) 204 .maxLines(1) 205 .fontSize(12) 206 .border({ width: 1 }) 207 .padding(10) 208 .marqueeOptions({ 209 start: true, 210 fromStart: true, 211 step: 6, 212 loop: -1, 213 delay: 0, 214 fadeout: false, 215 marqueeStartPolicy: MarqueeStartPolicy.DEFAULT 216 }) 217 ``` 218 219  220 221- 通过[lineHeight](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#lineheight)属性设置文本行高。 222 223 ```ts 224 Text('This is the text with the line height set. This is the text with the line height set.') 225 .width(300).fontSize(12).border({ width: 1 }).padding(10) 226 Text('This is the text with the line height set. This is the text with the line height set.') 227 .width(300).fontSize(12).border({ width: 1 }).padding(10) 228 .lineHeight(20) 229 ``` 230 231  232 233- 通过[decoration](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#decoration)属性设置文本装饰线样式、颜色及其粗细。 234 235 ```ts 236 Text('This is the text') 237 .decoration({ 238 type: TextDecorationType.LineThrough, 239 color: Color.Red 240 }) 241 .borderWidth(1).padding(15).margin(5) 242 Text('This is the text') 243 .decoration({ 244 type: TextDecorationType.Overline, 245 color: Color.Red 246 }) 247 .borderWidth(1).padding(15).margin(5) 248 Text('This is the text') 249 .decoration({ 250 type: TextDecorationType.Underline, 251 color: Color.Red 252 }) 253 .borderWidth(1).padding(15).margin(5) 254 Text('This is the text') 255 .decoration({ 256 type: TextDecorationType.Underline, 257 color: Color.Blue, 258 style: TextDecorationStyle.DASHED 259 }) 260 .borderWidth(1).padding(15).margin(5) 261 Text('This is the text') 262 .decoration({ 263 type: TextDecorationType.Underline, 264 color: Color.Blue, 265 style: TextDecorationStyle.DOTTED 266 }) 267 .borderWidth(1).padding(15).margin(5) 268 Text('This is the text') 269 .decoration({ 270 type: TextDecorationType.Underline, 271 color: Color.Blue, 272 style: TextDecorationStyle.DOUBLE 273 }) 274 .borderWidth(1).padding(15).margin(5) 275 Text('This is the text') 276 .decoration({ 277 type: TextDecorationType.Underline, 278 color: Color.Blue, 279 style: TextDecorationStyle.WAVY, 280 thicknessScale: 4 281 }) 282 .borderWidth(1).padding(15).margin(5) 283 ``` 284 285  286 287- 通过[baselineOffset](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#baselineoffset)属性设置文本基线的偏移量。 288 289 ```ts 290 Text('This is the text content with baselineOffset 0.') 291 .baselineOffset(0) 292 .fontSize(12) 293 .border({ width: 1 }) 294 .padding(10) 295 .width('100%') 296 .margin(5) 297 Text('This is the text content with baselineOffset 30.') 298 .baselineOffset(30) 299 .fontSize(12) 300 .border({ width: 1 }) 301 .padding(10) 302 .width('100%') 303 .margin(5) 304 Text('This is the text content with baselineOffset -20.') 305 .baselineOffset(-20) 306 .fontSize(12) 307 .border({ width: 1 }) 308 .padding(10) 309 .width('100%') 310 .margin(5) 311 ``` 312 313  314 315- 通过[letterSpacing](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#letterspacing)属性设置文本字符间距。 316 317 ```ts 318 Text('This is the text content with letterSpacing 0.') 319 .letterSpacing(0) 320 .fontSize(12) 321 .border({ width: 1 }) 322 .padding(10) 323 .width('100%') 324 .margin(5) 325 Text('This is the text content with letterSpacing 3.') 326 .letterSpacing(3) 327 .fontSize(12) 328 .border({ width: 1 }) 329 .padding(10) 330 .width('100%') 331 .margin(5) 332 Text('This is the text content with letterSpacing -1.') 333 .letterSpacing(-1) 334 .fontSize(12) 335 .border({ width: 1 }) 336 .padding(10) 337 .width('100%') 338 .margin(5) 339 ``` 340 341  342 343- 通过[minFontSize](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#minfontsize)与[maxFontSize](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#maxfontsize)自适应字体大小。 344 345 minFontSize用于设置文本的最小显示字号,maxFontSize用于设置文本的最大显示字号。这两个属性必须同时设置才能生效,并且需要与[maxLines](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#maxlines)属性或布局大小限制配合使用,单独设置任一属性将不会产生效果。 346 347 ```ts 348 Text('我的最大字号为30,最小字号为5,宽度为250,maxLines为1') 349 .width(250) 350 .maxLines(1) 351 .maxFontSize(30) 352 .minFontSize(5) 353 .border({ width: 1 }) 354 .padding(10) 355 .margin(5) 356 Text('我的最大字号为30,最小字号为5,宽度为250,maxLines为2') 357 .width(250) 358 .maxLines(2) 359 .maxFontSize(30) 360 .minFontSize(5) 361 .border({ width: 1 }) 362 .padding(10) 363 .margin(5) 364 Text('我的最大字号为30,最小字号为15,宽度为250,高度为50') 365 .width(250) 366 .height(50) 367 .maxFontSize(30) 368 .minFontSize(15) 369 .border({ width: 1 }) 370 .padding(10) 371 .margin(5) 372 Text('我的最大字号为30,最小字号为15,宽度为250,高度为100') 373 .width(250) 374 .height(100) 375 .maxFontSize(30) 376 .minFontSize(15) 377 .border({ width: 1 }) 378 .padding(10) 379 .margin(5) 380 ``` 381 382  383 384- 通过[textCase](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#textcase)属性设置文本大小写。 385 386 ```ts 387 Text('This is the text content with textCase set to Normal.') 388 .textCase(TextCase.Normal) 389 .padding(10) 390 .border({ width: 1 }) 391 .padding(10) 392 .margin(5) 393 // 文本全小写展示 394 Text('This is the text content with textCase set to LowerCase.') 395 .textCase(TextCase.LowerCase) 396 .border({ width: 1 }) 397 .padding(10) 398 .margin(5) 399 // 文本全大写展示 400 Text('This is the text content with textCase set to UpperCase.') 401 .textCase(TextCase.UpperCase) 402 .border({ width: 1 }) 403 .padding(10) 404 .margin(5) 405 ``` 406 407  408 409- 通过[copyOption](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#copyoption9)属性设置文本是否可复制粘贴。 410 411 ```ts 412 Text("这是一段可复制文本") 413 .fontSize(30) 414 .copyOption(CopyOptions.InApp) 415 ``` 416 417  418 419- 通过[fontFamily](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#fontfamily)属性设置字体列表。应用当前支持'HarmonyOS Sans'字体和[注册自定义字体](../reference/apis-arkui/js-apis-font.md)。 420 421 ```ts 422 Text("This is the text content with fontFamily") 423 .fontSize(30) 424 .fontFamily('HarmonyOS Sans') 425 ``` 426 427  428 429- 从API version 20开始,支持通过[contentTransition](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#contenttransition20)属性设置数字翻牌效果。 430 431 ```ts 432 @State number: number = 98; 433 @State numberTransition: NumericTextTransition = new NumericTextTransition({ flipDirection: FlipDirection.DOWN, enableBlur: false }); 434 435 Column() { 436 Text(this.number + "") 437 .borderWidth(1) 438 .fontSize(40) 439 .contentTransition(this.numberTransition) 440 Button("chang number") 441 .onClick(() => { 442 this.number++ 443 }) 444 .margin(10) 445 } 446 ``` 447  448 449- 从API version 20开始,支持通过[optimizeTrailingSpace](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#optimizetrailingspace20)设置是否在文本布局过程中优化每行末尾的空格,可解决行尾空格影响对齐显示效果问题。 450 451 ```ts 452 Column() { 453 //启用优化行尾空格功能 454 Text("Trimmed space enabled ") 455 .fontSize(30) 456 .fontWeight(FontWeight.Bold) 457 .margin({ top: 20 }) 458 .optimizeTrailingSpace(true) 459 .textAlign(TextAlign.Center) 460 //不启用优化行尾空格功能 461 Text("Trimmed space disabled ") 462 .fontSize(30) 463 .fontWeight(FontWeight.Bold) 464 .margin({ top: 20 }) 465 .optimizeTrailingSpace(false) 466 .textAlign(TextAlign.Center) 467 } 468 ``` 469  470 471- 从API version 20开始,支持通过[lineSpacing](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#linespacing20)设置文本的行间距。当不配置[LineSpacingOptions](../reference/apis-arkui/arkui-ts/ts-text-common.md#linespacingoptions20对象说明)时,首行上方和尾行下方默认会有行间距,当onlyBetweenLines设置为true时,行间距仅适用于行与行之间,首行上方无额外的行间距。 472 473 ```ts 474 import { LengthMetrics } from '@kit.ArkUI'; 475 476 @Extend(Text) 477 function style() { 478 .width(250) 479 .height(100) 480 .maxFontSize(30) 481 .minFontSize(15) 482 .border({ width: 1 }) 483 } 484 485 @Entry 486 @Component 487 struct demo { 488 build() { 489 Column() { 490 Text('The line spacing of this context is set to 20_px, and the spacing is effective only between the lines.') 491 .lineSpacing(LengthMetrics.px(20), { onlyBetweenLines: true }) 492 .style() 493 } 494 } 495 } 496 ``` 497  498 499- 从API version 20开始,支持通过[enableAutoSpacing](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#enableautospacing20)设置是否开启中文与西文的自动间距。 500 501 ```ts 502 @Entry 503 @Component 504 struct TextExample { 505 @State enableSpacing: boolean = false; 506 507 build() { 508 Column() { 509 Row({ space: 20 }) { 510 Button("开启自动间距") 511 .onClick(() => this.enableSpacing = true) 512 .backgroundColor(this.enableSpacing ? '#4CAF50' : '#E0E0E0') 513 .fontColor(this.enableSpacing ? Color.White : Color.Black) 514 515 Button("关闭自动间距") 516 .onClick(() => this.enableSpacing = false) 517 .backgroundColor(!this.enableSpacing ? '#F44336' : '#E0E0E0') 518 .fontColor(!this.enableSpacing ? Color.White : Color.Black) 519 } 520 .width('100%') 521 .justifyContent(FlexAlign.Center) 522 .margin({ top: 30, bottom: 20 }) 523 524 Text(this.enableSpacing ? "当前状态:已开启自动间距" : "当前状态:已关闭自动间距") 525 .fontSize(16) 526 .fontColor(this.enableSpacing ? '#4CAF50' : '#F44336') 527 .margin({ bottom: 20 }) 528 529 // 设置是否应用中西文自动间距 530 Text('中西文Auto Spacing自动间距') 531 .fontSize(24) 532 .padding(15) 533 .backgroundColor('#F5F5F5') 534 .width('90%') 535 .enableAutoSpacing(this.enableSpacing) 536 } 537 .width('100%') 538 .height('100%') 539 .padding(20) 540 } 541 } 542 ``` 543  544 545- 从API version 20开始,支持通过[ShaderStyle](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#shaderstyle20)设置渐变色。 546 547 ```ts 548 @State message: string = 'Hello World'; 549 @State linearGradientOptions: LinearGradientOptions = 550 { 551 direction: GradientDirection.LeftTop, 552 colors: [[Color.Red, 0.0], [Color.Blue, 0.3], [Color.Green, 0.5]], 553 repeating: true, 554 }; 555 556 Column({ space: 5 }) { 557 Text('direction为LeftTop的线性渐变').fontSize(18).width('90%').fontColor(0xCCCCCC) 558 .margin({ top: 40, left: 40 }) 559 Text(this.message) 560 .fontSize(50) 561 .width('80%') 562 .height(50) 563 .shaderStyle(this.linearGradientOptions) 564 } 565 ``` 566  567 568## 添加事件 569 570Text组件可以添加通用事件,可以绑定[onClick](../reference/apis-arkui/arkui-ts/ts-universal-events-click.md#onclick)、[onTouch](../reference/apis-arkui/arkui-ts/ts-universal-events-touch.md#ontouch)等事件来响应操作。 571 572```ts 573// xxx.ets 574@Entry 575@Component 576struct Index { 577 @State textStr1: string = ''; 578 @State textStr2: string = ''; 579 580 build() { 581 Row() { 582 Column() { 583 Text('This is a text component.') 584 .fontSize(30) 585 .onClick(() => { 586 console.info('Text onClick is triggering'); 587 this.textStr1 = 'Text onClick is triggering'; 588 }) 589 .onTouch(() => { 590 console.info('Text onTouch is triggering'); 591 this.textStr2 = 'Text onTouch is triggering'; 592 }) 593 Text('onClick:' + this.textStr1) 594 .fontSize(20) 595 Text('onTouch:' + this.textStr2) 596 .fontSize(20) 597 }.width('100%') 598 } 599 .height('100%') 600 } 601} 602``` 603 604 605 606## 设置垂直居中 607 608从API version 20开始,Text组件支持通过[textVerticalAlign](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#textverticalalign20)属性实现文本段落在垂直方向的对齐。 609 610 - 以下示例展示了如何通过textVerticalAlign属性设置文本垂直居中对齐效果。 611 612 ```ts 613 Text() { 614 Span("Hello") 615 .fontSize(50) 616 // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。 617 ImageSpan($r('app.media.startIcon')) 618 .width(30).height(30) 619 .verticalAlign(ImageSpanAlignment.FOLLOW_PARAGRAPH) 620 Span("World") 621 } 622 .textVerticalAlign(TextVerticalAlign.CENTER) 623 ``` 624 625  626 627## 设置选中菜单 628 629### 弹出选中菜单 630 631 - 设置Text被选中时,会弹出包含复制、翻译、搜索的菜单。 632 633 Text组件需要设置[copyOption](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#copyoption9)属性才可以被选中。 634 635 ```ts 636 Text("这是一段文本,用来展示选中菜单") 637 .fontSize(30) 638 .copyOption(CopyOptions.InApp) 639 ``` 640  641 642 - Text组件通过设置[bindSelectionMenu](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#bindselectionmenu11)属性绑定自定义选择菜单。 643 644 ```ts 645 controller:TextController = new TextController() 646 build() { 647 Column() { 648 Text("这是一段文本,用来展示选中菜单", {controller:this.controller}) 649 .fontSize(30) 650 .copyOption(CopyOptions.InApp) 651 .bindSelectionMenu(TextSpanType.TEXT, this.RightClickTextCustomMenu, TextResponseType.RIGHT_CLICK, { 652 onAppear: () => { 653 console.info('自定义选择菜单弹出时触发该回调'); 654 }, 655 onDisappear: () => { 656 console.info('自定义选择菜单关闭时触发该回调'); 657 } 658 }) 659 } 660 } 661 ``` 662 663 ```ts 664 // 定义菜单项 665 @Builder 666 RightClickTextCustomMenu() { 667 Column() { 668 Menu() { 669 MenuItemGroup() { 670 // $r('app.media.app_icon')需要替换为开发者所需的图像资源文件。 671 MenuItem({ startIcon: $r('app.media.app_icon'), content: "CustomMenu One", labelInfo: "" }) 672 .onClick(() => { 673 // 使用closeSelectionMenu接口关闭菜单 674 this.controller.closeSelectionMenu(); 675 }) 676 MenuItem({ startIcon: $r('app.media.app_icon'), content: "CustomMenu Two", labelInfo: "" }) 677 MenuItem({ startIcon: $r('app.media.app_icon'), content: "CustomMenu Three", labelInfo: "" }) 678 } 679 }.backgroundColor('#F0F0F0') 680 } 681 } 682 ``` 683  684 685 - Text组件通过设置[editMenuOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#editmenuoptions12)属性扩展自定义选择菜单,可以设置扩展项的文本内容、图标以及回调方法。 686 687 ```ts 688 Text('这是一段文本,用来展示选中菜单') 689 .fontSize(20) 690 .copyOption(CopyOptions.LocalDevice) 691 .editMenuOptions({ 692 onCreateMenu: this.onCreateMenu, onMenuItemClick: this.onMenuItemClick 693 }) 694 ``` 695 696 ```ts 697 // 定义onCreateMenu,onMenuItemClick 698 onCreateMenu = (menuItems: Array<TextMenuItem>) => { 699 // $r('app.media.app_icon')需要替换为开发者所需的图像资源文件。 700 let item1: TextMenuItem = { 701 content: 'customMenu1', 702 icon: $r('app.media.app_icon'), 703 id: TextMenuItemId.of('customMenu1'), 704 }; 705 let item2: TextMenuItem = { 706 content: 'customMenu2', 707 id: TextMenuItemId.of('customMenu2'), 708 icon: $r('app.media.app_icon'), 709 }; 710 menuItems.push(item1); 711 menuItems.unshift(item2); 712 return menuItems; 713 } 714 715 onMenuItemClick = (menuItem: TextMenuItem, textRange: TextRange) => { 716 if (menuItem.id.equals(TextMenuItemId.of("customMenu2"))) { 717 console.log("拦截 id: customMenu2 start:" + textRange.start + "; end:" + textRange.end); 718 return true; 719 } 720 if (menuItem.id.equals(TextMenuItemId.COPY)) { 721 console.log("拦截 COPY start:" + textRange.start + "; end:" + textRange.end); 722 return true; 723 } 724 if (menuItem.id.equals(TextMenuItemId.SELECT_ALL)) { 725 console.log("不拦截 SELECT_ALL start:" + textRange.start + "; end:" + textRange.end); 726 return false; 727 } 728 return false; 729 }; 730 ``` 731  732 733### 关闭选中菜单 734 735 使用Text组件时,若需要实现点击空白处关闭选中的场景,分为以下两种情况: 736 737 - 在Text组件区域内点击空白处,会正常关闭选中态和菜单; 738 - 在Text组件区域外点击空白处,前提是Text组件设置[selection](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#selection11)属性,具体示例如下: 739 740 ```ts 741 // xxx.ets 742 @Entry 743 @Component 744 struct Index { 745 @State text: string = 746 'This is set selection to Selection text content This is set selection to Selection text content.'; 747 @State start: number = 0; 748 @State end: number = 20; 749 750 build() { 751 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Start }) { 752 Text(this.text) 753 .fontSize(12) 754 .border({ width: 1 }) 755 .lineHeight(20) 756 .margin(30) 757 .copyOption(CopyOptions.InApp) 758 .selection(this.start, this.end) 759 .onTextSelectionChange((selectionStart, selectionEnd) => { 760 // 更新选中态位置 761 this.start = selectionStart; 762 this.end = selectionEnd; 763 }) 764 } 765 .height(600) 766 .width(335) 767 .borderWidth(1) 768 .onClick(() => { 769 // 监听父组件的点击事件,将选中首尾位置均设置为-1,即可清除选中 770 this.start = -1; 771 this.end = -1; 772 }) 773 } 774 } 775 ``` 776 777### 屏蔽系统服务类菜单 778 779- 从API version 20开始,支持通过[disableSystemServiceMenuItems](../reference/apis-arkui/arkts-apis-uicontext-textmenucontroller.md#disablesystemservicemenuitems20)屏蔽文本选择菜单内所有系统服务菜单项。 780 781 ```ts 782 import { TextMenuController } from '@kit.ArkUI'; 783 // xxx.ets 784 @Entry 785 @Component 786 struct Index { 787 aboutToAppear(): void { 788 // 禁用所有系统服务菜单 789 TextMenuController.disableSystemServiceMenuItems(true); 790 } 791 792 aboutToDisappear(): void { 793 // 页面消失恢复系统服务菜单 794 TextMenuController.disableSystemServiceMenuItems(false); 795 } 796 797 build() { 798 Row() { 799 Column() { 800 Text("这是一段文本,长按弹出文本选择菜单") 801 .height(60) 802 .fontStyle(FontStyle.Italic) 803 .fontWeight(FontWeight.Bold) 804 .textAlign(TextAlign.Center) 805 .copyOption(CopyOptions.InApp) 806 .editMenuOptions({ 807 onCreateMenu: (menuItems: Array<TextMenuItem>) => { 808 // menuItems不包含被屏蔽的系统菜单项 809 return menuItems; 810 }, 811 onMenuItemClick: (menuItem: TextMenuItem, textRange: TextRange) => { 812 return false; 813 } 814 }) 815 }.width('100%') 816 } 817 .height('100%') 818 } 819 } 820 ``` 821 822  823 824- 从API version 20开始,支持通过[disableMenuItems](../reference/apis-arkui/arkts-apis-uicontext-textmenucontroller.md#disablemenuitems20)屏蔽文本选择菜单内指定的系统服务菜单项。 825 826 ```ts 827 import { TextMenuController } from '@kit.ArkUI'; 828 // xxx.ets 829 @Entry 830 @Component 831 struct Index { 832 aboutToAppear(): void { 833 // 禁用搜索菜单 834 TextMenuController.disableMenuItems([TextMenuItemId.SEARCH]) 835 } 836 837 aboutToDisappear(): void { 838 // 恢复系统服务菜单 839 TextMenuController.disableMenuItems([]) 840 } 841 842 build() { 843 Row() { 844 Column() { 845 Text("这是一段文本,长按弹出文本选择菜单") 846 .height(60) 847 .fontStyle(FontStyle.Italic) 848 .fontWeight(FontWeight.Bold) 849 .textAlign(TextAlign.Center) 850 .copyOption(CopyOptions.InApp) 851 .editMenuOptions({ 852 onCreateMenu: (menuItems: Array<TextMenuItem>) => { 853 // menuItems不包含搜索 854 return menuItems; 855 }, 856 onMenuItemClick: (menuItem: TextMenuItem, textRange: TextRange) => { 857 return false 858 } 859 }) 860 }.width('100%') 861 } 862 .height('100%') 863 } 864 } 865 ``` 866 867  868 869### 默认菜单支持自定义刷新能力 870 871从API version 20开始,当文本选择区域变化后显示菜单之前触发[onPrepareMenu](../reference/apis-arkui/arkui-ts/ts-text-common.md#onpreparemenu20)回调,可在该回调中进行菜单数据设置。 872 873```ts 874// xxx.ets 875@Entry 876@Component 877struct TextExample12 { 878 @State text: string = 'Text editMenuOptions'; 879 @State endIndex: number = 0; 880 onCreateMenu = (menuItems: Array<TextMenuItem>) => { 881 // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。 882 let item1: TextMenuItem = { 883 content: 'create1', 884 icon: $r('app.media.startIcon'), 885 id: TextMenuItemId.of('create1'), 886 }; 887 let item2: TextMenuItem = { 888 content: 'create2', 889 id: TextMenuItemId.of('create2'), 890 icon: $r('app.media.startIcon'), 891 }; 892 menuItems.push(item1); 893 menuItems.unshift(item2); 894 return menuItems; 895 } 896 onMenuItemClick = (menuItem: TextMenuItem, textRange: TextRange) => { 897 if (menuItem.id.equals(TextMenuItemId.of("create2"))) { 898 console.log("拦截 id: create2 start:" + textRange.start + "; end:" + textRange.end); 899 return true; 900 } 901 if (menuItem.id.equals(TextMenuItemId.of("prepare1"))) { 902 console.log("拦截 id: prepare1 start:" + textRange.start + "; end:" + textRange.end); 903 return true; 904 } 905 if (menuItem.id.equals(TextMenuItemId.COPY)) { 906 console.log("拦截 COPY start:" + textRange.start + "; end:" + textRange.end); 907 return true; 908 } 909 if (menuItem.id.equals(TextMenuItemId.SELECT_ALL)) { 910 console.log("不拦截 SELECT_ALL start:" + textRange.start + "; end:" + textRange.end); 911 return false; 912 } 913 return false; 914 } 915 // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。 916 onPrepareMenu = (menuItems: Array<TextMenuItem>) => { 917 let item1: TextMenuItem = { 918 content: 'prepare1_' + this.endIndex, 919 icon: $r('app.media.startIcon'), 920 id: TextMenuItemId.of('prepare1'), 921 }; 922 menuItems.unshift(item1); 923 return menuItems; 924 } 925 @State editMenuOptions: EditMenuOptions = { 926 onCreateMenu: this.onCreateMenu, 927 onMenuItemClick: this.onMenuItemClick, 928 onPrepareMenu: this.onPrepareMenu 929 }; 930 931 build() { 932 Column() { 933 Text(this.text) 934 .fontSize(20) 935 .copyOption(CopyOptions.LocalDevice) 936 .editMenuOptions(this.editMenuOptions) 937 .margin({ top: 100 }) 938 .onTextSelectionChange((selectionStart: number, selectionEnd: number) => { 939 this.endIndex = selectionEnd; 940 }) 941 } 942 .width("90%") 943 .margin("5%") 944 } 945} 946``` 947 948 949 950## 设置AI菜单 951 952Text组件通过[enableDataDetector](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#enabledatadetector11)和[dataDetectorConfig](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#datadetectorconfig11)属性实现AI菜单的显示。AI菜单的表现形式包括:单击AI实体(指可被识别的内容,包括地址、邮箱等)弹出菜单的实体识别选项,选中文本后,文本选择菜单与鼠标右键菜单中显示的实体识别选项。 953 954> **说明:** 955> 956> 从API version 20开始,支持在文本选择菜单与鼠标右键菜单中显示实体识别选项。当[enableDataDetector](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#enabledatadetector11)设置为true,且[copyOption](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#copyoption9)设置为CopyOptions.LocalDevice时,该功能生效。菜单选项包括[TextMenuItemId](../reference/apis-arkui/arkui-ts/ts-text-common.md#textmenuitemid12)中的url(打开链接)、email(新建邮件)、phoneNumber(呼叫)、address(导航至该位置)、dateTime(新建日程提醒)。 957> 958> 该功能生效时,需选中范围内,包括一个完整的AI实体,才能展示对应的选项。 959 960- 如果需要单击AI实体弹出菜单的实体识别选项,可以配置[enableDataDetector](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#enabledatadetector11)为true。 961- 如果在单击的交互方式之外,还需要文本选择菜单与鼠标右键菜单中显示的实体识别选项,可以配置[enableDataDetector](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#enabledatadetector11)为true,且[copyOption](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#copyoption9)设置为CopyOptions.LocalDevice,具体示例如下所示: 962 ```ts 963 Text( 964 '电话号码:' + '(86) (755) ********' + '\n' + 965 '链接:' + 'www.********.com' + '\n' + 966 '邮箱:' + '***@example.com' + '\n' + 967 '地址:' + 'XX省XX市XX区XXXX' + '\n' + 968 '时间:' + 'XX年XX月XX日XXXX' 969 ) 970 .fontSize(16) 971 .copyOption(CopyOptions.LocalDevice) 972 .enableDataDetector(true)// 使能实体识别 973 .dataDetectorConfig({ 974 // 配置识别样式 975 // types可支持PHONE_NUMBER电话号码、URL链接、EMAIL邮箱、ADDRESS地址、DATE_TIME时间 976 // types设置为null或者[]时,识别所有类型的实体 977 types: [], onDetectResultUpdate: (result: string) => { 978 } 979 }) 980 ``` 981- 如果需要调整识别出的样式,可以通过[dataDetectorConfig](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#datadetectorconfig11)实现,具体可以参考[TextDataDetectorConfig](../reference/apis-arkui/arkui-ts/ts-text-common.md#textdatadetectorconfig11对象说明)配置项。 982- 如果需要调整菜单的位置,可以通过[editMenuOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#editmenuoptions12)实现,具体可以参考示例[文本扩展自定义菜单](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#示例12文本扩展自定义菜单)。 983<!--RP2--><!--RP2End--> 984 985## 场景示例 986 987该示例通过maxLines、textOverflow、textAlign、constraintSize属性展示了热搜榜的效果。 988 989```ts 990// xxx.ets 991@Entry 992@Component 993struct TextExample { 994 build() { 995 Column() { 996 Row() { 997 Text("1").fontSize(14).fontColor(Color.Red).margin({ left: 10, right: 10 }) 998 Text("我是热搜词条1") 999 .fontSize(12) 1000 .fontColor(Color.Blue) 1001 .maxLines(1) 1002 .textOverflow({ overflow: TextOverflow.Ellipsis }) 1003 .fontWeight(300) 1004 Text("爆") 1005 .margin({ left: 6 }) 1006 .textAlign(TextAlign.Center) 1007 .fontSize(10) 1008 .fontColor(Color.White) 1009 .fontWeight(600) 1010 .backgroundColor(0x770100) 1011 .borderRadius(5) 1012 .width(15) 1013 .height(14) 1014 }.width('100%').margin(5) 1015 1016 Row() { 1017 Text("2").fontSize(14).fontColor(Color.Red).margin({ left: 10, right: 10 }) 1018 Text("我是热搜词条2 我是热搜词条2 我是热搜词条2 我是热搜词条2 我是热搜词条2") 1019 .fontSize(12) 1020 .fontColor(Color.Blue) 1021 .fontWeight(300) 1022 .constraintSize({ maxWidth: 200 }) 1023 .maxLines(1) 1024 .textOverflow({ overflow: TextOverflow.Ellipsis }) 1025 Text("热") 1026 .margin({ left: 6 }) 1027 .textAlign(TextAlign.Center) 1028 .fontSize(10) 1029 .fontColor(Color.White) 1030 .fontWeight(600) 1031 .backgroundColor(0xCC5500) 1032 .borderRadius(5) 1033 .width(15) 1034 .height(14) 1035 }.width('100%').margin(5) 1036 1037 Row() { 1038 Text("3").fontSize(14).fontColor(Color.Orange).margin({ left: 10, right: 10 }) 1039 Text("我是热搜词条3") 1040 .fontSize(12) 1041 .fontColor(Color.Blue) 1042 .fontWeight(300) 1043 .maxLines(1) 1044 .constraintSize({ maxWidth: 200 }) 1045 .textOverflow({ overflow: TextOverflow.Ellipsis }) 1046 Text("热") 1047 .margin({ left: 6 }) 1048 .textAlign(TextAlign.Center) 1049 .fontSize(10) 1050 .fontColor(Color.White) 1051 .fontWeight(600) 1052 .backgroundColor(0xCC5500) 1053 .borderRadius(5) 1054 .width(15) 1055 .height(14) 1056 }.width('100%').margin(5) 1057 1058 Row() { 1059 Text("4").fontSize(14).fontColor(Color.Grey).margin({ left: 10, right: 10 }) 1060 Text("我是热搜词条4 我是热搜词条4 我是热搜词条4 我是热搜词条4 我是热搜词条4") 1061 .fontSize(12) 1062 .fontColor(Color.Blue) 1063 .fontWeight(300) 1064 .constraintSize({ maxWidth: 200 }) 1065 .maxLines(1) 1066 .textOverflow({ overflow: TextOverflow.Ellipsis }) 1067 }.width('100%').margin(5) 1068 }.width('100%') 1069 } 1070} 1071 1072``` 1073 1074 1075<!--RP1--><!--RP1End--> 1076 1077## 常见问题 1078 1079### Text组件尾部省略号后为什么还有一段空白,没有占满组件宽度 1080 1081**问题现象** 1082 1083在Text组件上未设置宽度,当内容过长时,省略号与组件边缘之间会留有较大空白,且内容更新时省略号的位置会发生变化。 1084 1085 1086 1087**原因分析** 1088 1089当Text组件未设置宽度且内容超长时,组件宽度将采用父组件传递的布局约束的最大宽度。省略开始位置会根据不同的断词模式导致排版塑型结果有所不同,因此不同内容的省略开始位置也会不同。 1090 1091**解决措施** 1092 1093设置[wordBreak](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#wordbreak11)属性为`WordBreak.BREAK_ALL`,任意2个字符间断行使文本内容尽量占满组件区域。 1094 1095示例代码如下: 1096```ts 1097@Entry 1098@Component 1099struct Index { 1100 @State message: string = '混合Hello World! honorificabilitudinitatibus!'; 1101 1102 build() { 1103 Column() { 1104 Text(this.message) 1105 .id('HelloWorld') 1106 .fontSize('25fp') 1107 .maxLines(1) 1108 .textOverflow({ overflow: TextOverflow.Ellipsis}) 1109 .onClick(() => { 1110 this.message = 'Welcome try try try 1235628327434348'; 1111 }) 1112 .border({ width: 1}) 1113 .wordBreak(WordBreak.BREAK_ALL) // 修改断词模式 1114 } 1115 .width(300) 1116 .border({ width: 1, color: Color.Blue}) 1117 .margin({left: 30, top: 50}) 1118 } 1119} 1120``` 1121 1122### Text组件如何实现行末展开样式 1123 1124**解决措施** 1125 1126自行测算截断字符,并在行末添加`...展开`或者`...图标`作为组件内容。 1127 1128**参考链接** 1129 1130[属性字符串转Paragraph数组](../reference/apis-arkui/arkts-apis-uicontext-measureutils.md#getparagraphs20) 1131<!--RP3--><!--RP3End--> 1132 1133### Text组件如何实现不设置maxLines在固定布局约束下内容超出仍显示省略样式 1134 1135**问题现象** 1136 1137在固定尺寸的组件区域内,不同字号的内容显示的最大行数会有所不同。期望实现内容超长时自动显示省略样式,则无需设置固定的`maxLines`值。 1138 1139**解决措施** 1140 1141设置[heightAdaptivePolicy](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#heightadaptivepolicy10)为TextHeightAdaptivePolicy.LAYOUT_CONSTRAINT_FIRST,该模式会删除超过布局约束的行,从而实现类似设置maxLines的效果。 1142 1143示例代码如下: 1144```ts 1145@Entry 1146@Component 1147struct Index { 1148 @State message: string = '混合Hello World! 多行文本 中英文数字混合 1282378283 ~'; 1149 @State fontSize: number = 25; 1150 1151 build() { 1152 Column({ space: 10 }) { 1153 Text(this.message) 1154 .id('HelloWorld') 1155 .fontSize(this.fontSize) 1156 .textOverflow({ overflow: TextOverflow.Ellipsis}) 1157 .border({ width: 1}) 1158 .heightAdaptivePolicy(TextHeightAdaptivePolicy.LAYOUT_CONSTRAINT_FIRST) // 调整自适应布局策略 1159 .width(300) 1160 .height(200) 1161 Row(){ 1162 Button('fontSize+5') 1163 .onClick(()=>{ 1164 this.fontSize += 5; 1165 }) 1166 Button('fontSize-5') 1167 .onClick(()=>{ 1168 this.fontSize -= 5; 1169 }) 1170 } 1171 } 1172 .margin({left: 30, top: 50}) 1173 } 1174} 1175``` 1176 1177