1# RichEditor 2 3The **RichEditor** is a component that supports interactive text editing and mixture of text and imagery. 4 5> **NOTE** 6> 7> This component is supported since API version 10. Updates will be marked with a superscript to indicate their earliest API version. 8 9 10## Child Components 11 12Not supported 13 14 15## APIs 16 17RichEditor(value: RichEditorOptions) 18 19**Atomic service API**: This API can be used in atomic services since API version 11. 20 21**Parameters** 22 23| Name | Type | Mandatory | Description | 24| ----- | --------------------------------------- | ---- | ----------- | 25| value | [RichEditorOptions](#richeditoroptions) | Yes | Options for initializing the component. | 26 27RichEditor(options: RichEditorStyledStringOptions)<sup>12+</sup> 28 29 30**Parameters** 31 32| Name | Type | Mandatory | Description | 33| ----- | --------------------------------------- | ---- | ----------- | 34| options | [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) | Yes | Options for initializing the component. | 35 36## Attributes 37 38In addition to the [universal attributes](ts-universal-attributes-size.md), the following attributes are supported. 39 40> **NOTE** 41> 42> The **align** attribute supports only the start, center, and end options. 43 44### customKeyboard 45 46customKeyboard(value: CustomBuilder, options?: KeyboardOptions) 47 48Sets a custom keyboard. 49 50When a custom keyboard is set, activating the text box opens the specified custom component, instead of the system input method. 51 52The custom keyboard's height can be set through the **height** attribute of the custom component's root node, and its width is fixed at the default value. 53 54The custom keyboard is displayed on top of the current page, without compressing or raising the page. 55 56The custom keyboard cannot obtain focus, but it blocks gesture events. 57 58By default, the custom keyboard is closed when the input component loses the focus. 59 60When a custom keyboard is set, the text box does not support camera input, even when the device supports. 61 62**Atomic service API**: This API can be used in atomic services since API version 11. 63 64**System capability**: SystemCapability.ArkUI.ArkUI.Full 65 66**Parameters** 67 68| Name | Type | Mandatory | Description | 69| --------------------- | ------------------------------------------- | ---- | -------------------------------- | 70| value | [CustomBuilder](ts-types.md#custombuilder8) | Yes | Custom keyboard.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 71| options<sup>12+</sup> | [KeyboardOptions](#keyboardoptions12) | No | Whether to support keyboard avoidance. | 72 73### bindSelectionMenu 74 75bindSelectionMenu(spanType: RichEditorSpanType, content: CustomBuilder, responseType: ResponseType | RichEditorResponseType, 76 options?: SelectionMenuOptions) 77 78Sets the custom context menu on text selection. If the custom menu is too long, embed a [Scroll](./ts-container-scroll.md) component to prevent the keyboard from being blocked. 79 80**Atomic service API**: This API can be used in atomic services since API version 11. 81 82**System capability**: SystemCapability.ArkUI.ArkUI.Full 83 84**Parameters** 85 86| Name | Type | Mandatory | Description | 87| ------------ | ------------------------------------------------------------ | ---- | --------------------------------------------------------- | 88| spanType | [RichEditorSpanType](#richeditorspantype) | Yes | Menu type.<br> Default value:<br>RichEditorSpanType.TEXT | 89| content | [CustomBuilder](ts-types.md#custombuilder8) | Yes | Menu content. | 90| responseType | [ResponseType](ts-appendix-enums.md#responsetype8) \| [RichEditorResponseType<sup>11+</sup>](ts-appendix-enums.md#richeditorresponsetype11) | Yes | Response type of the menu.<br> Default value:<br>ResponseType.LongPress | 91| options | [SelectionMenuOptions](#selectionmenuoptions11) | No | Menu options. | 92 93### copyOptions 94 95copyOptions(value: CopyOptions) 96 97Specifies whether copy and paste is allowed for text content. 98 99If **copyOptions** is not set to **CopyOptions.None**, long-pressing the text content displays the context menu. If a custom context menu is defined through **bindSelectionMenu** or other approaches, it will be displayed. 100 101If **copyOptions** is set to **CopyOptions.None**, copy and paste is not allowed. 102 103**Atomic service API**: This API can be used in atomic services since API version 11. 104 105**System capability**: SystemCapability.ArkUI.ArkUI.Full 106 107**Parameters** 108 109| Name | Type | Mandatory | Description | 110| ------ | ------------------------------------------------ | ---- | ------------------------------------------------------------ | 111| value | [CopyOptions](ts-appendix-enums.md#copyoptions9) | Yes | Whether copy and paste is allowed for text content.<br>Default value: **CopyOptions.LocalDevice** | 112 113### enableDataDetector<sup>11+</sup> 114 115enableDataDetector(enable: boolean) 116 117Enables text recognition. 118 119The recognized entity is in the following style settings:<br>fontColor: Color.Blue<br>decoration: {<br>type: TextDecorationType.Underline,<br>color: Color.Blue<br>} 120 121For this API to work, the target device must provide the text recognition capability. 122 123When **enableDataDetector** is set to **true** and **dataDetectorConfig** is not set, all types of entities are recognized by default. 124 125When **copyOptions** is set to **CopyOptions.None**, the menu displayed after an entity is clicked does not provide text selection. 126 127This API does not work for the node text of **addBuilderSpan**. 128 129**Atomic service API**: This API can be used in atomic services since API version 12. 130 131**System capability**: SystemCapability.ArkUI.ArkUI.Full 132 133**Parameters** 134 135| Name | Type | Mandatory | Description | 136| ------ | ------- | ---- | --------------------------------- | 137| enable | boolean | Yes | Whether to enable text recognition.<br>Default value: **false** | 138 139### dataDetectorConfig<sup>11+</sup> 140 141dataDetectorConfig(config: TextDataDetectorConfig) 142 143Configures text recognition settings. This API must be used together with [enableDataDetector](#enabledatadetector11). It takes effect only when **enableDataDetector** is set to **true**. 144 145**Atomic service API**: This API can be used in atomic services since API version 12. 146 147**System capability**: SystemCapability.ArkUI.ArkUI.Full 148 149**Parameters** 150 151| Name | Type | Mandatory | Description | 152| ------ | --------------------------------------------------- | ---- | ------------------------------------------------------------ | 153| config | [TextDataDetectorConfig](#textdatadetectorconfig11) | Yes | Text recognition configuration.<br>Default value: {<br>types: [ ],<br>onDetectResultUpdate: null<br>} | 154 155### enablePreviewText<sup>12+</sup> 156 157enablePreviewText(enable: boolean) 158 159Sets whether to enable preview text. 160 161**Atomic service API**: This API can be used in atomic services since API version 12. 162 163**System capability**: SystemCapability.ArkUI.ArkUI.Full 164 165**Parameters** 166 167| Name | Type | Mandatory | Description | 168| ------ | ------- | ---- | --------------------------------- | 169| enable | boolean | Yes | Whether to enable preview text.<br>Default value: **true** | 170 171### placeholder<sup>12+</sup> 172 173placeholder(value: ResourceStr, style?: PlaceholderStyle) 174 175Sets the placeholder text, which is displayed when there is no input. 176 177**Atomic service API**: This API can be used in atomic services since API version 12. 178 179**System capability**: SystemCapability.ArkUI.ArkUI.Full 180 181**Parameters** 182 183| Name | Type | Mandatory | Description | 184| ------ | --------------------------------------- | ---- | ------------------------------------------------------- | 185| value | [ResourceStr](ts-types.md#resourcestr) | Yes | Placeholder text. | 186| style | [PlaceholderStyle](#placeholderstyle12) | No | Style of the placeholder text.<br>By default, the style follows the theme. | 187 188### caretColor<sup>12+</sup> 189 190caretColor(value: ResourceColor) 191 192Sets the color of the caret and selection handle in the text box. 193 194**Atomic service API**: This API can be used in atomic services since API version 12. 195 196**System capability**: SystemCapability.ArkUI.ArkUI.Full 197 198**Parameters** 199 200| Name | Type | Mandatory | Description | 201| ------ | ------------------------------------------ | ---- | -------------------------------------- | 202| value | [ResourceColor](ts-types.md#resourcecolor) | Yes | Color of the cursor and selection handle in the text box.<br>Default value: **'#007DFF'** | 203 204### selectedBackgroundColor<sup>12+</sup> 205 206selectedBackgroundColor(value: ResourceColor) 207 208Sets the background color of the selected text. If the opacity is not set, a 20% opacity will be used. 209 210**Atomic service API**: This API can be used in atomic services since API version 12. 211 212**System capability**: SystemCapability.ArkUI.ArkUI.Full 213 214**Parameters** 215 216| Name | Type | Mandatory | Description | 217| ------ | ------------------------------------------ | ---- | ------------------------------------------ | 218| value | [ResourceColor](ts-types.md#resourcecolor) | Yes | Background color of the selected text.<br>By default, a 20% opacity is applied. | 219 220### editMenuOptions<sup>12+</sup> 221 222editMenuOptions(editMenu: EditMenuOptions) 223 224Sets the extended options of the custom context menu on selection, including the text content, icon, and callback. 225 226**Atomic service API**: This API can be used in atomic services since API version 12. 227 228**System capability**: SystemCapability.ArkUI.ArkUI.Full 229 230**Parameters** 231 232| Name | Type | Mandatory | Description | 233| ------ | --------------------------------------------- | ---- | --------------------------------------------- | 234| editMenu | [EditMenuOptions](ts-text-common.md#editmenuoptions) | No | Extended options of the custom context menu on selection. | 235 236### enterKeyType<sup>12+</sup> 237 238enterKeyType(value: EnterKeyType) 239 240Sets the Enter key type of the soft keyboard. 241 242**Atomic service API**: This API can be used in atomic services since API version 12. 243 244**System capability**: SystemCapability.ArkUI.ArkUI.Full 245 246**Parameters** 247 248| Name | Type | Mandatory | Description | 249| ------ | ------ | ---- | ----------------------------------- | 250| value | [EnterKeyType](ts-types.md#enterkeytype) | Yes | Type of the Enter key.<br>Default value: **EnterKeyType.NEW_LINE** | 251 252### enableKeyboardOnFocus<sup>13+</sup> 253 254enableKeyboardOnFocus(isEnabled: boolean) 255 256Sets whether to enable the input method when the **RichEditor** component obtains focus in a way other than clicking. 257 258 259**Atomic service API**: This API can be used in atomic services since API version 13. 260 261**System capability**: SystemCapability.ArkUI.ArkUI.Full 262 263**Parameters** 264 265| Name | Type | Mandatory | Description | 266| ------ | ------- | ---- | ----------------------------------------------------------- | 267| isEnabled | boolean | Yes | Whether to enable the input method when the component obtains focus in a way other than clicking.<br>Default value: **true** | 268 269## Events 270 271In addition to the [universal events](ts-universal-events-click.md), the following events are supported. 272 273### onReady 274 275onReady(callback:Callback\<void\>) 276 277Triggered when initialization of the component is completed. 278 279**Atomic service API**: This API can be used in atomic services since API version 11. 280 281**System capability**: SystemCapability.ArkUI.ArkUI.Full 282 283**Parameters** 284 285| Name | Type | Mandatory | Description | 286| ----- | --------------------------------------- | ---- | ----------- | 287| callback |Callback\<void\> | Yes | Invoked when initialization of the **RichEditor** component is complete. | 288 289### onSelect 290 291onSelect(callback:Callback\<[RichEditorSelection](#richeditorselection)\>) 292 293Invoked when content is selected. 294 295If a mouse device is used for selection, this callback is invoked when the mouse button is released. If a finger is used for selection, this callback is invoked when the finger is released. 296 297This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used. 298 299**Atomic service API**: This API can be used in atomic services since API version 11. 300 301**System capability**: SystemCapability.ArkUI.ArkUI.Full 302 303**Parameters** 304 305| Name | Type | Mandatory | Description | 306| ------ | ------------------------------------------- | ---- | -------------------- | 307| callback | Callback\<[RichEditorSelection](#richeditorselection)\> | Yes | Callback invoked when content is selected.<br>[RichEditorSelection](#richeditorselection) indicates information about all the selected spans. | 308 309### aboutToIMEInput 310 311aboutToIMEInput(callback:Callback\<[RichEditorInsertValue](#richeditorinsertvalue), boolean\>) 312 313Invoked when content is about to be entered in the input method. 314 315This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used. 316 317**Atomic service API**: This API can be used in atomic services since API version 11. 318 319**System capability**: SystemCapability.ArkUI.ArkUI.Full 320 321**Parameters** 322 323| Name | Type | Mandatory | Description | 324| ------ | ------------------------------------------- | ---- | -------------------- | 325| callback | Callback\<[RichEditorInsertValue](#richeditorinsertvalue), boolean\> | Yes | Callback invoked when content is about to be entered in the input method.<br/>[RichEditorInsertValue](#richeditorinsertvalue) indicates whether content will be entered in the input method.<br>**true**: Content is inserted.<br>**false**: Content is not inserted. | 326 327### onIMEInputComplete 328 329onIMEInputComplete(callback:Callback\<[RichEditorTextSpanResult](#richeditortextspanresult)\>) 330 331Invoked when text input in the input method is complete. 332 333This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used. 334 335**Atomic service API**: This API can be used in atomic services since API version 11. 336 337**System capability**: SystemCapability.ArkUI.ArkUI.Full 338 339**Parameters** 340 341| Name | Type | Mandatory | Description | 342| ------ | ------------------------------------------- | ---- | -------------------- | 343| callback | Callback\<[RichEditorTextSpanResult](#richeditortextspanresult)\> | Yes | Callback invoked when text input in the input method is complete.<br/>[RichEditorTextSpanResult](#richeditortextspanresult) indicates the text span information after text input is complete. | 344 345### aboutToDelete 346 347aboutToDelete(callback:Callback\<[RichEditorDeleteValue](#richeditordeletevalue), boolean\>) 348 349Invoked when content is about to be deleted in the input method. 350 351This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used. 352 353**Atomic service API**: This API can be used in atomic services since API version 11. 354 355**System capability**: SystemCapability.ArkUI.ArkUI.Full 356 357**Parameters** 358 359| Name | Type | Mandatory | Description | 360| ------ | ------------------------------------------- | ---- | -------------------- | 361| callback | Callback\<[RichEditorDeleteValue](#richeditordeletevalue), boolean\> | Yes | Callback invoked when content is about to be deleted in the input method.<br/>[RichEditorDeleteValue](#richeditordeletevalue) indicates the text or image span where the content to be deleted is located.<br>**true**: Content is deleted.<br>**false**: Content is not deleted. | 362 363### onDeleteComplete 364 365onDeleteComplete(callback:Callback\<void\>) 366 367Invoked when deletion in the input method is completed. 368 369This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used. 370 371**Atomic service API**: This API can be used in atomic services since API version 11. 372 373**System capability**: SystemCapability.ArkUI.ArkUI.Full 374 375**Parameters** 376 377| Name | Type | Mandatory | Description | 378| ----- | --------------------------------------- | ---- | ----------- | 379| callback |Callback\<void\> | Yes | Callback invoked when deletion in the input method is completed. | 380 381### onPaste<sup>11+</sup> 382 383onPaste(callback: [PasteEventCallback](#pasteeventcallback12) ) 384 385Invoked when the paste is about to be completed. By default, only plain text can be pasted. You can use this API to overwrite the default system behavior so that both images and text can be pasted. 386 387**Atomic service API**: This API can be used in atomic services since API version 12. 388 389**System capability**: SystemCapability.ArkUI.ArkUI.Full 390 391**Parameters** 392 393| Name | Type | Mandatory | Description | 394| ------ | ------- | ---- | ----------------------------- | 395| callback | [PasteEventCallback](#pasteeventcallback12) | Yes | Callback invoked when the paste is about to be completed. | 396 397### onSelectionChange<sup>12+</sup> 398 399onSelectionChange(callback:Callback\<[RichEditorRange](#richeditorrange)\>) 400 401Invoked when the content selection area changes or the caret position changes in the editing state. In the case of caret position changes, the start position of the content selection area is equal to the end position. 402 403**Atomic service API**: This API can be used in atomic services since API version 12. 404 405**System capability**: SystemCapability.ArkUI.ArkUI.Full 406 407**Parameters** 408 409| Name | Type | Mandatory | Description | 410| ----- | --------------------------------------- | ---- | ----------- | 411| callback |Callback\<[RichEditorRange](#richeditorrange)\> | Yes | Callback invoked when the content selection area changes or the caret position changes in the editing state.<br/>[RichEditorRange](#richeditorrange) indicates the start and end positions of the content selection area. | 412 413### onEditingChange<sup>12+</sup> 414 415onEditingChange(callback: Callback\<boolean\>) 416 417Invoked when the editing state of all content in the component changes. 418 419**Atomic service API**: This API can be used in atomic services since API version 12. 420 421**System capability**: SystemCapability.ArkUI.ArkUI.Full 422 423**Parameters** 424 425| Name | Type | Mandatory | Description | 426| ----- | --------------------------------------- | ---- | ----------- | 427| callback | Callback\<boolean\> | Yes | Callback invoked when the editing state of all content in the component changes. The value **true** indicates the editing state, and **false** indicates the non-editing state. | 428 429### onSubmit<sup>12+</sup> 430 431onSubmit(callback: SubmitCallback) 432 433Invoked when the Enter key on the soft keyboard is pressed. 434 435**Atomic service API**: This API can be used in atomic services since API version 12. 436 437**System capability**: SystemCapability.ArkUI.ArkUI.Full 438 439**Parameters** 440 441| Name | Type | Mandatory | Description | 442| ------ | ------- | ---- | ----------------------------- | 443| callback | [SubmitCallback](#submitcallback12) | Yes | Callback used to return the result. | 444 445### onWillChange<sup>12+</sup> 446 447onWillChange(callback: Callback\<RichEditorChangeValue, boolean\>) 448 449Invoked when the text or image in the component is about to change. 450 451This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used. 452 453**Atomic service API**: This API can be used in atomic services since API version 12. 454 455**System capability**: SystemCapability.ArkUI.ArkUI.Full 456 457**Parameters** 458 459| Name | Type | Mandatory | Description | 460| -- | -- | -- | -- | 461| callback | Callback\<[RichEditorChangeValue](#richeditorchangevalue12) , boolean\> | Yes | [RichEditorChangeValue](#richeditorchangevalue12) indicates the text and image change information. **boolean** indicates whether the current text and images are allowed to be changed. The value **true** means that the text and images are allowed to be changed, and **false** means the opposite. | 462 463### onDidChange<sup>12+</sup> 464 465onDidChange(callback: OnDidChangeCallback) 466 467Invoked after the text or image in the component changes. 468 469This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used. 470 471**Atomic service API**: This API can be used in atomic services since API version 12. 472 473**System capability**: SystemCapability.ArkUI.ArkUI.Full 474 475**Parameters** 476 477| Name | Type | Mandatory | Description | 478| -- | -- | -- | -- | 479| callback | [OnDidChangeCallback](#ondidchangecallback12) | Yes | Content range before and after the text and image change. | 480 481### onCut<sup>12+</sup> 482 483onCut(callback: Callback\<CutEvent\>) 484 485Invoked when text is about to be cut. By default, only plain text can be cut. You can use this method to override the system's default behavior and implement the cutting of text and images. 486 487**Atomic service API**: This API can be used in atomic services since API version 12. 488 489**System capability**: SystemCapability.ArkUI.ArkUI.Full 490 491**Parameters** 492 493| Name | Type | Mandatory | Description | 494| ----- | --------------------------------------- | ---- | ----------- | 495| callback |Callback\<[CutEvent](#cutevent12)\> | Yes | Defines a custom cut event. | 496 497### onCopy<sup>12+</sup> 498 499onCopy(callback: Callback\<CopyEvent\>) 500 501Invoked when text is about to be copied. By default, only plain text can be copied. You can use this method to override the system's default behavior and implement the copying of text and images. 502 503**Atomic service API**: This API can be used in atomic services since API version 12. 504 505**System capability**: SystemCapability.ArkUI.ArkUI.Full 506 507**Parameters** 508 509| Name | Type | Mandatory | Description | 510| ----- | --------------------------------------- | ---- | ----------- | 511| callback |Callback\<[CopyEvent](#copyevent12)\> | Yes | User copy event. | 512 513## RichEditorInsertValue 514 515Describes the text to be inserted. 516 517 518 519**System capability**: SystemCapability.ArkUI.ArkUI.Full 520 521| Name | Type | Mandatory | Description | 522| ------------ | ------ | ---- | ---------- | 523| insertOffset | number | Yes | Offset of the text to be inserted.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 524| insertValue | string | Yes | Content of the text to be inserted.<br>**Atomic service API**: This API can be used in atomic services since API version 11. | 525| previewText<sup>12+</sup> | string | No | Content of the preview text to be inserted.<br> **Atomic service API**: This API can be used in atomic services since API version 12.| 526 527 528## RichEditorDeleteValue 529 530Provides information about the delete operation and the deleted content. 531 532**Atomic service API**: This API can be used in atomic services since API version 11. 533 534**System capability**: SystemCapability.ArkUI.ArkUI.Full 535 536| Name | Type | Mandatory | Description | 537| --------------------- | ---------------------------------------- | ---- | ------------------- | 538| offset | number | Yes | Offset of the deleted content. | 539| direction | [RichEditorDeleteDirection](#richeditordeletedirection) | Yes | Direction of the delete operation. | 540| length | number | Yes | Length of the deleted content. | 541| richEditorDeleteSpans | Array<[RichEditorTextSpanResult](#richeditortextspanresult) \| [RichEditorImageSpanResult](#richeditorimagespanresult)> | Yes | Information about the deleted text or image span. | 542 543 544## RichEditorDeleteDirection 545 546Enumerates the directions of the delete operation. 547 548**Atomic service API**: This API can be used in atomic services since API version 11. 549 550**System capability**: SystemCapability.ArkUI.ArkUI.Full 551 552| Name | Description | 553| -------- | ----- | 554| BACKWARD | Backward. | 555| FORWARD | Forward. | 556 557 558## RichEditorTextSpanResult 559 560Provides the text span information. 561 562**System capability**: SystemCapability.ArkUI.ArkUI.Full 563 564| Name | Type | Mandatory | Description | 565| ----------------------------- | ---------------------------------------- | ---- | ---------------------- | 566| spanPosition | [RichEditorSpanPosition](#richeditorspanposition) | Yes | Span position.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 567| value | string | Yes | Text span content.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 568| textStyle | [RichEditorTextStyleResult](#richeditortextstyleresult) | Yes | Text span style.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 569| offsetInSpan | [number, number] | Yes | Start and end positions of the valid content in the text span.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 570| valueResource<sup>11+</sup> | [Resource](ts-types.md#resource) | No | Content of the **\<SymbolSpan>** component.<br>**Atomic service API**: This API can be used in atomic services since API version 12. | 571| SymbolSpanStyle<sup>11+</sup> | [RichEditorSymbolSpanStyle](#richeditorsymbolspanstyle11) | No | Style of the **\<SymbolSpan>** component.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 572| paragraphStyle<sup>12+</sup> | [RichEditorParagraphStyle](#richeditorparagraphstyle11) | No | Paragraph style.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 573| previewText<sup>12+</sup> | string | No | Content of the preview text.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 574 575 576## RichEditorSpanPosition 577 578Provides the span position information. 579 580**Atomic service API**: This API can be used in atomic services since API version 11. 581 582**System capability**: SystemCapability.ArkUI.ArkUI.Full 583 584| Name | Type | Mandatory | Description | 585| --------- | ---------------- | ---- | --------------------------- | 586| spanIndex | number | Yes | Span index. | 587| spanRange | [number, number] | Yes | Start and end positions of the span content in the **RichEditor** component. | 588 589## RichEditorSpanType 590 591Provides the span type information. 592 593**Atomic service API**: This API can be used in atomic services since API version 11. 594 595**System capability**: SystemCapability.ArkUI.ArkUI.Full 596 597| Name | Value | Description | 598| ----- | ---- | ------------ | 599| TEXT | 0 | Text span. | 600| IMAGE | 1 | Image span. | 601| MIXED | 2 | Mixed span, which contains both text and imagery. | 602 603## RichEditorTextStyleResult 604 605Provides the text span style information returned by the backend. 606 607**System capability**: SystemCapability.ArkUI.ArkUI.Full 608 609| Name | Type | Mandatory | Description | 610| ---------- | ---------------------------------------- | ---- | ------------ | 611| fontColor | [ResourceColor](ts-types.md#resourcecolor) | Yes | Font color.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 612| fontSize | number | Yes | Font size. The default unit is fp.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 613| fontStyle | [FontStyle](ts-appendix-enums.md#fontstyle) | Yes | Font style.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 614| fontWeight | number | Yes | Font weight.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 615| fontFamily | string | Yes | Font family.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 616| decoration | [DecorationStyleResult](ts-universal-styled-string.md#decorationstyleresult) | Yes | Text decorative line.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 617| lineHeight<sup>12+</sup> | number | No | Line height. The default unit is fp.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 618| letterSpacing<sup>12+</sup>| number | No | Letter spacing. The default unit is fp.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 619| fontFeature<sup>12+</sup> | string | No | Font feature.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 620 621> **NOTE** 622> 623> While **fontWeight** in **RichEditorTextStyle** sets the font weight, 624> **fontWeight** in **RichEditorTextStyleResult** returns the set font weight after conversion to digits. 625> The table below lists the conversion mappings. 626> 627> | fontWeight in RichEditorTextStyle | fontWeight in RichEditorTextStyleResult | 628> | ---- | ----------------------------------- | 629> | 100 | 0 | 630> | 200 | 1 | 631> | 300 | 2 | 632> | 400 | 3 | 633> | 500 | 4 | 634> | 600 | 5 | 635> | 700 | 6 | 636> | 800 | 7 | 637> | 900 | 8 | 638> | Lighter | 12 | 639> | Normal | 10 | 640> | Regular | 14 | 641> | Medium | 13 | 642> | Bold | 9 | 643> | Bolder | 11 | 644> 645> The conversion mappings between the **fontWeight** parameters in **RichEditorSymbolSpanStyle** and **RichEditorSymbolSpanStyleResult** 646> are the same as those between the **fontWeight** parameters in **RichEditorTextStyle** and **RichEditorTextStyleResult**. 647 648## RichEditorSymbolSpanStyleResult<sup>11+</sup> 649 650Provides the symbol span style information returned by the backend. 651 652**Atomic service API**: This API can be used in atomic services since API version 12. 653 654**System capability**: SystemCapability.ArkUI.ArkUI.Full 655 656| Name | Type | Mandatory | Description | 657| ------ | -------- | ---- | -------------------------------------- | 658| fontColor | Array\<[ResourceColor](ts-types.md#resourcecolor)\> | No | Color of the symbol span.<br> Default value: depending on the rendering strategy | 659| fontSize | number \| string \| [Resource](ts-types.md#resource) | No | Size of the symbol span. The default unit is fp.<br>The default value follows the theme.| 660| fontWeight | [FontWeight](ts-appendix-enums.md#fontweight) \| number \| string | No | Weight of the symbol span.<br>For the number type, the value ranges from 100 to 900, at an interval of 100. A larger value indicates a heavier font weight. The default value is **400**.<br>For the string type, only strings of the number type are supported, for example, **"400"**, **"bold"**, **"bolder"**, **"lighter"**, **"regular"**, and **"medium"**, which correspond to the enumerated values in **FontWeight**.<br>Default value: **FontWeight.Normal**| 661| renderingStrategy | [SymbolRenderingStrategy](ts-appendix-enums.md#symbolrenderingstrategy11) | No | Rendering strategy of the symbol span.<br>Default value: **SymbolRenderingStrategy.SINGLE**<br>**NOTE**<br>For the resources referenced in **$r('sys.symbol.ohos_*')**, only **ohos_folder_badge_plus** supports the **MULTIPLE_COLOR** and **MULTIPLE_OPACITY** modes.| 662| effectStrategy | [SymbolEffectStrategy](ts-appendix-enums.md#symboleffectstrategy11) | No | Effect strategy of the symbol span.<br>Default value: **SymbolEffectStrategy.NONE**<br>**NOTE**<br>For the resources referenced in **$r('sys.symbol.ohos_*')**, only **ohos_wifi** supports the hierarchical effect.| 663 664## RichEditorImageSpanResult 665 666Provides the image information returned by the backend. 667 668**Atomic service API**: This API can be used in atomic services since API version 11. 669 670**System capability**: SystemCapability.ArkUI.ArkUI.Full 671 672| Name | Type | Mandatory | Description | 673|------------------|-------------------------------------------------------------------|-----|------------------| 674| spanPosition | [RichEditorSpanPosition](#richeditorspanposition) | Yes | Span position.| 675| valuePixelMap | [PixelMap](../../apis-image-kit/js-apis-image.md#pixelmap7) | No | Image content.| 676| valueResourceStr | [ResourceStr](ts-types.md#resourcestr) | No | Image resource ID.| 677| imageStyle | [RichEditorImageSpanStyleResult](#richeditorimagespanstyleresult) | Yes | Image style.| 678| offsetInSpan | [number, number] | Yes | Start and end positions of the image in the span.| 679 680## RichEditorImageSpanStyleResult 681 682Provides the image span style information returned by the backend. 683 684**System capability**: SystemCapability.ArkUI.ArkUI.Full 685 686| Name | Type | Mandatory | Description | 687| ------------- | ---------------------------------------- | ---- | --------- | 688| size | [number, number] | Yes | Width and height of the image, in px. Default value: varies by the value of **objectFit**. If the value of **objectFit** is **Cover**, the image height is the component height minus the top and bottom paddings, and the image width is the component width minus the left and right paddings.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 689| verticalAlign | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | Yes | Vertical alignment mode of the image.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 690| objectFit | [ImageFit](ts-appendix-enums.md#imagefit) | Yes | Scale mode of the image.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 691| layoutStyle<sup>12+</sup> | [RichEditorLayoutStyle](#richeditorlayoutstyle11) | No | Image layout style. | 692 693## RichEditorLayoutStyle<sup>11+</sup> 694 695**Atomic service API**: This API can be used in atomic services since API version 12. 696 697**System capability**: SystemCapability.ArkUI.ArkUI.Full 698 699|Name |Type |Mandatory| Description| 700| ------------- | ----------------------- | ---- | ------------------------------------------------------------ | 701|margin | [Dimension](ts-types.md#dimension10) \| [Margin](ts-types.md#margin) | No | Margins in different directions of the component.<br>When the parameter is of the **Dimension** type, the four margins take effect.| 702|borderRadius | [Dimension](ts-types.md#dimension10) \| [BorderRadiuses](ts-types.md#borderradiuses9) | No | Radius of the rounded corners of the component.<br>If of the **Dimension** type, this parameter cannot be set in percentage.| 703 704## RichEditorOptions 705 706Defines the options for initializing the **RichEditor** component. 707 708**Atomic service API**: This API can be used in atomic services since API version 11. 709 710**System capability**: SystemCapability.ArkUI.ArkUI.Full 711 712| Name | Type | Mandatory | Description | 713| ---------- | ---------------------------------------- | ---- | ------- | 714| controller | [RichEditorController](#richeditorcontroller) | Yes | Controller for the **RichEditor** component. | 715 716## RichEditorStyledStringOptions<sup>12+</sup> 717 718Defines the options for initializing the **RichEditor** component. 719 720**Atomic service API**: This API can be used in atomic services since API version 12. 721 722**System capability**: SystemCapability.ArkUI.ArkUI.Full 723 724| Name | Type | Mandatory | Description | 725| ---------- | ---------------------------------------- | ---- | ------- | 726| controller | [RichEditorStyledStringController](#richeditorstyledstringcontroller12) | Yes | Controller for the **RichEditor** component. | 727 728## SelectionOptions<sup>12+</sup> 729 730Defines options for **setSelection**. 731 732**Atomic service API**: This API can be used in atomic services since API version 12. 733 734**System capability**: SystemCapability.ArkUI.ArkUI.Full 735 736| Name | Type | Mandatory | Description | 737| ---------- | ---------------------------------------- | ---- | ------- | 738| menuPolicy | [MenuPolicy](ts-appendix-enums.md#menupolicy12) | No | Menu display policy. | 739 740## TextDataDetectorConfig<sup>11+</sup> 741 742Provides the text recognition configuration. 743 744**System capability**: SystemCapability.ArkUI.ArkUI.Full 745 746| Name | Type | Mandatory | Description | 747| ---------- |-----------------------------------------------------------------------| ---- | ------- | 748| types | [TextDataDetectorType](ts-appendix-enums.md#textdatadetectortype11)[] | Yes | Entity types for text recognition. Values **null** and **[]** indicate that all types of entities can be recognized. | 749| onDetectResultUpdate | (result: string) => void | No | Callback invoked when text recognition succeeds.<br>**result**: text recognition result, in JSON format. | 750 751## RichEditorChangeValue<sup>12+</sup> 752 753**Atomic service API**: This API can be used in atomic services since API version 12. 754 755| Name | Type | Mandatory | Description | 756| --------------------- | ---------------------------------------- | ---- | ------------------- | 757| rangeBefore | [TextRange](ts-text-common.md#textrange12) | Yes | Information about the text span before the change. | 758| replacedSpans | Array<[RichEditorTextSpanResult](#richeditortextspanresult)> | Yes | Information about the text span after the change. | 759| replacedImageSpans | Array<[RichEditorImageSpanResult](#richeditorimagespanresult)> | Yes | Information about the image span after the change. | 760| replacedSymbolSpans | Array<[RichEditorTextSpanResult](#richeditortextspanresult)> | Yes | Information about the symbol span after the change. | 761 762## RichEditorBaseController<sup>12+</sup> 763 764Represents the base class of the **RichEditor** component controller. 765 766### getCaretOffset<sup>12+</sup> 767 768getCaretOffset(): number 769 770Obtains the current cursor position. 771 772**Atomic service API**: This API can be used in atomic services since API version 11. 773 774**System capability**: SystemCapability.ArkUI.ArkUI.Full 775 776**Return value** 777 778| Type | Description | 779| ------ | --------- | 780| number | Cursor position. | 781 782### setCaretOffset<sup>12+</sup> 783 784setCaretOffset(offset: number): boolean 785 786Sets the cursor position. 787 788**Atomic service API**: This API can be used in atomic services since API version 11. 789 790**System capability**: SystemCapability.ArkUI.ArkUI.Full 791 792**Parameters** 793 794| Name | Type | Mandatory | Description | 795| ------ | ------ | ---- | -------------------- | 796| offset | number | Yes | Offset of the cursor. If it exceeds the range of all content, the setting will fail. | 797 798**Return value** 799 800| Type | Description | 801| ------- | --------- | 802| boolean | Whether the cursor position is set successfully. | 803 804### closeSelectionMenu<sup>12+</sup> 805 806closeSelectionMenu(): void 807 808Closes the custom or default context menu on selection. 809 810**System capability**: SystemCapability.ArkUI.ArkUI.Full 811 812 813### getTypingStyle<sup>12+</sup> 814 815getTypingStyle(): RichEditorTextStyle 816 817Obtains the preset typing style. 818 819**Atomic service API**: This API can be used in atomic services since API version 12. 820 821**System capability**: SystemCapability.ArkUI.ArkUI.Full 822 823**Return value** 824 825| Type | Description | 826| ---------------------------------------- | ------- | 827| [RichEditorTextStyle](#richeditortextstyle) | Preset typing style. | 828 829### setTypingStyle<sup>12+</sup> 830 831setTypingStyle(value: RichEditorTextStyle): void 832 833Sets the typing style. 834 835**Atomic service API**: This API can be used in atomic services since API version 12. 836 837**System capability**: SystemCapability.ArkUI.ArkUI.Full 838 839**Parameters** 840 841| Name | Type | Mandatory | Description | 842| ----- | ---------------------------------------- | ---- | ----- | 843| value | [RichEditorTextStyle](#richeditortextstyle) | Yes | Typing style to set. | 844 845### setSelection<sup>12+</sup> 846 847setSelection(selectionStart: number, selectionEnd: number, options?: SelectionOptions): void 848 849Sets the range of content selection. The selected content is highlighted. 850 851If both **selectionStart** and **selectionEnd** are set to **-1**, all text is selected. 852 853If this API is called when the text box is not focused, the selected effect is not displayed. 854 855Since API version 12, on 2-in-1 devices, regardless of the value of **options**, calling the **setSelection** API will not display the menu. In addition, if there is already a menu present within the component, calling the **setSelection** API will close the menu. 856 857On non-2-in-1 devices, when **options** is set to **MenuPolicy.DEFAULT**, the following rules apply: 858 8591. If the component has a selection handle menu, calling the API will not close the menu, and the menu position will be adjusted. 860 8612. If the component has a menu without a selection handle, calling the API will not close the menu, and the menu position will remain unchanged. 862 8633. If there is no menu within the component, calling the API will not display the menu. 864 865**Atomic service API**: This API can be used in atomic services since API version 12. 866 867**System capability**: SystemCapability.ArkUI.ArkUI.Full 868 869**Parameters** 870 871| Name | Type | Mandatory | Description | 872| -------------- | ------ | ---- | ------- | 873| selectionStart | number | Yes | Start position of the text selection. | 874| selectionEnd | number | Yes | End position of the text selection. | 875| options<sup>12+</sup> | [SelectionOptions](#selectionoptions12) | No | Configuration of options. | 876 877### isEditing<sup>12+</sup> 878 879isEditing(): boolean 880 881Obtains the editing state of this **RichEditor** component. 882 883**Atomic service API**: This API can be used in atomic services since API version 12. 884 885**System capability**: SystemCapability.ArkUI.ArkUI.Full 886 887**Return value** 888 889| Type | Description | 890| ------- | ----------------------------- | 891| boolean | Editing state. The value **true** indicates the editing state, and **false** indicates the non-editing state. | 892 893### stopEditing<sup>12+</sup> 894 895stopEditing(): void 896 897Exits the editing state. 898 899**Atomic service API**: This API can be used in atomic services since API version 12. 900 901**System capability**: SystemCapability.ArkUI.ArkUI.Full 902 903### getLayoutManager<sup>12+</sup> 904 905getLayoutManager(): LayoutManager 906 907Obtains a **LayoutManager** object. 908 909**System capability**: SystemCapability.ArkUI.ArkUI.Full 910 911**Return value** 912 913| Type | Description | 914| ---------------------------------------- | ------- | 915| [LayoutManager](ts-text-common.md#LayoutManager12) | **LayoutManager** object. | 916 917### getPreviewText<sup>12+</sup> 918 919getPreviewText(): PreviewText 920 921Obtains the preview text. 922 923**System capability**: SystemCapability.ArkUI.ArkUI.Full 924 925**Return value** 926 927| Type | Description | 928| ---------------------------------------- | ------- | 929| [PreviewText](#previewtext12) | Preview text. | 930 931## RichEditorController 932 933Implements the **RichEditor** component controller. Inherits from [RichEditorBaseController](#richeditorbasecontroller12). 934 935### Objects to Import 936 937``` 938controller: RichEditorController = new RichEditorController() 939``` 940 941### getCaretOffset 942 943getCaretOffset(): number 944 945Obtains the current cursor position. 946 947**Atomic service API**: This API can be used in atomic services since API version 11. 948 949**System capability**: SystemCapability.ArkUI.ArkUI.Full 950 951**Return value** 952 953| Type | Description | 954| ------ | --------- | 955| number | Cursor position. | 956 957### setCaretOffset 958 959setCaretOffset(offset: number): boolean 960 961Sets the cursor position. 962 963**Atomic service API**: This API can be used in atomic services since API version 11. 964 965**System capability**: SystemCapability.ArkUI.ArkUI.Full 966 967**Parameters** 968 969| Name | Type | Mandatory | Description | 970| ------ | ------ | ---- | -------------------- | 971| offset | number | Yes | Offset of the cursor. If the value is out of the text range, the setting fails. | 972 973**Return value** 974 975| Type | Description | 976| ------- | --------- | 977| boolean | Whether the cursor position is set successfully. | 978 979### addTextSpan 980 981addTextSpan(value: string, options?: RichEditorTextSpanOptions): number 982 983Adds a text span. If the cursor in the component is blinking, the cursor position is updated to be after the inserted text span. 984 985**Atomic service API**: This API can be used in atomic services since API version 11. 986 987**System capability**: SystemCapability.ArkUI.ArkUI.Full 988 989**Parameters** 990 991| Name | Type | Mandatory | Description | 992| ------- | ---------------------------------------- | ---- | ----- | 993| value | string | Yes | Text content. | 994| options | [RichEditorTextSpanOptions](#richeditortextspanoptions) | No | Text options. | 995 996**Return value** 997 998| Type | Description | 999| ------ | -------------------- | 1000| number | Position of the added text span. | 1001 1002### addImageSpan 1003 1004addImageSpan(value: PixelMap | ResourceStr, options?: RichEditorImageSpanOptions): number 1005 1006Adds an image span. If the cursor in the component is blinking, the cursor position is updated to be after the inserted image span. 1007 1008**Atomic service API**: This API can be used in atomic services since API version 11. 1009 1010**System capability**: SystemCapability.ArkUI.ArkUI.Full 1011 1012**Parameters** 1013 1014| Name | Type | Mandatory | Description | 1015| ------- | ---------------------------------------- | ---- | ----- | 1016| value | [PixelMap](../../apis-image-kit/js-apis-image.md#pixelmap7)\|[ResourceStr](ts-types.md#resourcestr) | Yes | Image content. | 1017| options | [RichEditorImageSpanOptions](#richeditorimagespanoptions) | No | Image options. | 1018 1019**Return value** 1020 1021| Type | Description | 1022| ------ | -------------------- | 1023| number | Position of the added image span. | 1024 1025### addBuilderSpan<sup>11+</sup> 1026 1027addBuilderSpan(value: CustomBuilder, options?: RichEditorBuilderSpanOptions): number 1028 1029> **NOTE** 1030> 1031> - This API adds a builder span to take up space in the layout. It calls the system **measure** method to calculate the actual length, width, and position. 1032> - You can use [RichEditorBuilderSpanOptions](#richeditorbuilderspanoptions11) to set the index of the builder in the **RichEditor** component (with one character as the unit). 1033> - This builder span is not focusable. It supports dragging and some universal attributes. Its capabilities regarding placeholder and deletion are equivalent to the image span, and its length is considered as one character. 1034> - The builder span does not allow for custom menus set through [bindSelectionMenu](#attributes). 1035> - The information about the builder span cannot be obtained through [getSpans](#getspans), [getSelection](#getselection11), [onSelect](#events), or [aboutToDelete](#events). 1036> - The builder span cannot be updated using [updateSpanStyle](#updatespanstyle) or [updateParagraphStyle](#updateparagraphstyle11). 1037> - Copying or pasting the builder span does not take effect. 1038> - The layout constraints of the builder span are passed in from the **RichEditor** component. If the size of the outermost component in the builder span is not set, the size of the **RichEditor** is used as the value of **maxSize**. 1039> - The gesture event mechanism of the builder span is the same as the universal gesture event mechanism. If transparent transmission is not set in the builder, only the child components in the builder respond. 1040> - If the cursor in the component is blinking, the cursor position is updated to be after the inserted image span. 1041 1042The following universal attributes are supported: [size](ts-universal-attributes-size.md#size), [padding](ts-universal-attributes-size.md#padding), [margin](ts-universal-attributes-size.md#margin), [aspectRatio](ts-universal-attributes-layout-constraints.md#aspectratio), [borderStyle](ts-universal-attributes-border.md#borderstyle), [borderWidth](ts-universal-attributes-border.md#borderwidth), [borderColor](ts-universal-attributes-border.md#bordercolor), [borderRadius](ts-universal-attributes-border.md#borderradius), [backgroundColor](ts-universal-attributes-background.md#backgroundcolor), [backgroundBlurStyle](ts-universal-attributes-background.md#backgroundblurstyle9), [opacity](ts-universal-attributes-opacity.md), [blur](ts-universal-attributes-image-effect.md#blur), [backdropBlur](ts-universal-attributes-image-effect.md#backdropblur), [shadow](ts-universal-attributes-image-effect.md#shadow), [grayscale](ts-universal-attributes-image-effect.md#grayscale), [brightness](ts-universal-attributes-image-effect.md#brightness), [saturate](ts-universal-attributes-image-effect.md#saturate), 1043[contrast](ts-universal-attributes-image-effect.md#contrast), [invert](ts-universal-attributes-image-effect.md#invert), [sepia](ts-universal-attributes-image-effect.md#sepia), [hueRotate](ts-universal-attributes-image-effect.md#huerotate), [colorBlend](ts-universal-attributes-image-effect.md#colorblend7), [linearGradientBlur](ts-universal-attributes-image-effect.md#lineargradientblur12), [clip](ts-universal-attributes-sharp-clipping.md#clip), [mask](ts-universal-attributes-sharp-clipping.md#mask), [foregroundBlurStyle](ts-universal-attributes-foreground-blur-style.md#foregroundblurstyle), [accessibilityGroup](ts-universal-attributes-accessibility.md#accessibilitygroup), [accessibilityText](ts-universal-attributes-accessibility.md#accessibilitytext), [accessibilityDescription](ts-universal-attributes-accessibility.md#accessibilitydescription), [accessibilityLevel](ts-universal-attributes-accessibility.md#accessibilitylevel), [sphericalEffect](ts-universal-attributes-image-effect.md#sphericaleffect12), [lightUpEffect](ts-universal-attributes-image-effect.md#lightupeffect12), [pixelStretchEffect](ts-universal-attributes-image-effect.md#pixelstretcheffect12) 1044 1045**Atomic service API**: This API can be used in atomic services since API version 12. 1046 1047**System capability**: SystemCapability.ArkUI.ArkUI.Full 1048 1049**Parameters** 1050 1051| Name | Type | Mandatory | Description | 1052| ------- | ---------------------------------------- | ---- | ---------- | 1053| value | [CustomBuilder](ts-types.md#custombuilder8) | Yes | Custom component. | 1054| options | [RichEditorBuilderSpanOptions](#richeditorbuilderspanoptions11) | No | Builder options. | 1055 1056**Return value** 1057 1058| Type | Description | 1059| ------ | ---------------------- | 1060| number | Position of the added builder span. | 1061 1062### addSymbolSpan<sup>11+</sup> 1063 1064addSymbolSpan(value: Resource, options?: RichEditorSymbolSpanOptions ): number 1065 1066Adds a symbol image. If the cursor in the component is blinking, the cursor position is updated to be after the inserted symbol span. 1067 1068Currently, gestures, copying, and dragging are not supported. 1069 1070**Atomic service API**: This API can be used in atomic services since API version 12. 1071 1072**System capability**: SystemCapability.ArkUI.ArkUI.Full 1073 1074**Parameters** 1075 1076| Name | Type | Mandatory | Description | 1077| ------- | ---------------------------------------- | ---- | ----- | 1078| value | [Resource](ts-types.md#resource) | Yes | Content of the symbol span. | 1079| options | [RichEditorSymbolSpanOptions](#richeditorsymbolspanoptions11) | No | Options of the symbol span. | 1080 1081**Return value** 1082 1083| Type | Description | 1084| ------ | --------------------- | 1085| number | Position of the added symbol span. | 1086 1087### getTypingStyle<sup>11+</sup> 1088 1089getTypingStyle(): RichEditorTextStyle 1090 1091Obtains the preset typing style. 1092 1093**Atomic service API**: This API can be used in atomic services since API version 12. 1094 1095**System capability**: SystemCapability.ArkUI.ArkUI.Full 1096 1097**Return value** 1098 1099| Type | Description | 1100| ---------------------------------------- | ------- | 1101| [RichEditorTextStyle](#richeditortextstyle) | Preset typing style. | 1102 1103### setTypingStyle<sup>11+</sup> 1104 1105setTypingStyle(value: RichEditorTextStyle): void 1106 1107Sets the typing style. 1108 1109When the default value (**undefined**/**null**) is used or this API is not called:<br> 1110- When users type into a **RichEditor** component with no text content using the keyboard, the typed text is displayed in the default style. For the default style, see [RichEditorTextStyle](#richeditortextstyle).<br> 1111- When users type into a **RichEditor** component with existing text content using the keyboard, the typed text follows the style of the preceding text and is not displayed in the default style. 1112 1113When a non-default value is used:<br> 1114- When users type into the **RichEditor** component using the keyboard, the text is displayed in the style set by you. If there are attributes in the preset style that have not been set, they use default values of [RichEditorTextStyle](#richeditortextstyle). 1115 1116**Atomic service API**: This API can be used in atomic services since API version 12. 1117 1118**System capability**: SystemCapability.ArkUI.ArkUI.Full 1119 1120**Parameters** 1121 1122| Name | Type | Mandatory | Description | 1123| ----- | ---------------------------------------- | ---- | ----- | 1124| value | [RichEditorTextStyle](#richeditortextstyle) | Yes | Typing style to set. | 1125 1126### updateSpanStyle 1127 1128updateSpanStyle(value: RichEditorUpdateTextSpanStyleOptions | RichEditorUpdateImageSpanStyleOptions | RichEditorUpdateSymbolSpanStyleOptions): void 1129 1130Updates the text, image, or symbol span style.<br>If only part of a span is updated, the span is split into multiple spans based on the updated part and the non-updated part. 1131 1132Calling this API will not close the custom context menu on selection by default. 1133 1134**Atomic service API**: This API can be used in atomic services since API version 11. 1135 1136**System capability**: SystemCapability.ArkUI.ArkUI.Full 1137 1138**Parameters** 1139 1140| Name | Type | Mandatory | Description | 1141| ------ | -------- | ---- | -------------------------------------- | 1142| value | [RichEditorUpdateTextSpanStyleOptions](#richeditorupdatetextspanstyleoptions) \| [RichEditorUpdateImageSpanStyleOptions](#richeditorupdateimagespanstyleoptions) \| [RichEditorUpdateSymbolSpanStyleOptions](#richeditorupdatesymbolspanstyleoptions11)<sup>11+</sup> | Yes | Style options of the text, image, or symbol span. | 1143 1144### updateParagraphStyle<sup>11+</sup> 1145 1146updateParagraphStyle(value: RichEditorParagraphStyleOptions): void 1147 1148Updates the paragraph style. 1149 1150**Atomic service API**: This API can be used in atomic services since API version 12. 1151 1152**System capability**: SystemCapability.ArkUI.ArkUI.Full 1153 1154**Parameters** 1155 1156| Name | Type | Mandatory | Description | 1157| ----- | ---------------------------------------- | ---- | ---------- | 1158| value | [RichEditorParagraphStyleOptions](#richeditorparagraphstyleoptions11) | Yes | Information about the paragraph style. | 1159 1160### getSpans 1161 1162getSpans(value?: RichEditorRange): Array<RichEditorTextSpanResult| RichEditorImageSpanResult> 1163 1164Obtains span information. 1165 1166**Atomic service API**: This API can be used in atomic services since API version 11. 1167 1168**System capability**: SystemCapability.ArkUI.ArkUI.Full 1169 1170**Parameters** 1171 1172| Name | Type | Mandatory | Description | 1173| ----- | ----------------------------------- | ---- | ----------- | 1174| value | [RichEditorRange](#richeditorrange) | No | Range of the target span. | 1175 1176**Return value** 1177 1178| Type | Description | 1179| ---------------------------------------- | ------------ | 1180| Array<[RichEditorTextSpanResult](#richeditortextspanresult) \| [RichEditorImageSpanResult](#richeditorimagespanresult)> | Text and image span information. | 1181 1182### deleteSpans 1183 1184deleteSpans(value?: RichEditorRange): void 1185 1186Deletes the text and image spans in a specified range. 1187 1188**Atomic service API**: This API can be used in atomic services since API version 11. 1189 1190**System capability**: SystemCapability.ArkUI.ArkUI.Full 1191 1192**Parameters** 1193 1194| Name | Type | Mandatory | Description | 1195| ----- | ----------------------------------- | ---- | ------------------- | 1196| value | [RichEditorRange](#richeditorrange) | No | Range of the target spans. If this parameter is left empty, all text and image spans will be deleted. | 1197 1198### getParagraphs<sup>11+</sup> 1199 1200getParagraphs(value?: RichEditorRange): Array\<RichEditorParagraphResult> 1201 1202Obtains the specified paragraphs. 1203 1204**Atomic service API**: This API can be used in atomic services since API version 12. 1205 1206**System capability**: SystemCapability.ArkUI.ArkUI.Full 1207 1208**Parameters** 1209 1210| Name | Type | Mandatory | Description | 1211| ----- | ----------------------------------- | ---- | ---------- | 1212| value | [RichEditorRange](#richeditorrange) | No | Range of the paragraphs to obtain. | 1213 1214**Return value** 1215 1216| Type | Description | 1217| ---------------------------------------- | -------- | 1218| Array\<[RichEditorParagraphResult](#richeditorparagraphresult11)> | Information about the selected paragraphs. | 1219 1220### closeSelectionMenu 1221 1222closeSelectionMenu(): void 1223 1224Closes the custom or default context menu on selection. 1225 1226**Atomic service API**: This API can be used in atomic services since API version 11. 1227 1228**System capability**: SystemCapability.ArkUI.ArkUI.Full 1229 1230### setSelection<sup>11+</sup> 1231 1232setSelection(selectionStart: number, selectionEnd: number, options?: SelectionOptions): void 1233 1234Sets the range of the current text selection. The selected text is highlighted. 1235 1236If both **selectionStart** and **selectionEnd** are set to **-1**, all text is selected. 1237 1238If this API is called when the text box is not focused, the selected effect is not displayed. 1239 1240Since API version 12, on 2-in-1 devices, regardless of the value of **options**, calling the **setSelection** API will not display the menu. In addition, if there is already a menu present within the component, calling the **setSelection** API will close the menu. 1241 1242On non-2-in-1 devices, when **options** is set to **MenuPolicy.DEFAULT**, the following rules apply: 1243 12441. If the component has a selection handle menu, calling the API will not close the menu, and the menu position will be adjusted. 1245 12462. If the component has a menu without a selection handle, calling the API will not close the menu, and the menu position will remain unchanged. 1247 12483. If there is no menu within the component, calling the API will not display the menu. 1249 1250For details, see [Example](ohos-arkui-advanced-SelectionMenu.md#example). 1251 1252**Atomic service API**: This API can be used in atomic services since API version 12. 1253 1254**System capability**: SystemCapability.ArkUI.ArkUI.Full 1255 1256**Parameters** 1257 1258| Name | Type | Mandatory | Description | 1259| -------------- | ------ | ---- | ------- | 1260| selectionStart | number | Yes | Start position of the text selection. | 1261| selectionEnd | number | Yes | End position of the text selection. | 1262| options<sup>12+</sup> | [SelectionOptions](#selectionoptions12) | No | Configuration of options. | 1263 1264### getSelection<sup>11+</sup> 1265 1266getSelection(): RichEditorSelection 1267 1268Obtains the selected content. If no text is selected, the information about the span where the caret is located is returned. 1269 1270**Atomic service API**: This API can be used in atomic services since API version 12. 1271 1272**System capability**: SystemCapability.ArkUI.ArkUI.Full 1273 1274**Return value** 1275 1276| Type | Description | 1277| ---------------------------------------- | ------- | 1278| [RichEditorSelection](#richeditorselection) | Provides information about the selected content. | 1279 1280### fromStyledString<sup>12+</sup> 1281 1282fromStyledString(value: StyledString): Array\<RichEditorSpan> 1283 1284Converts a styled string into a span. 1285 1286**Atomic service API**: This API can be used in atomic services since API version 12. 1287 1288**System capability**: SystemCapability.ArkUI.ArkUI.Full 1289 1290**Parameters** 1291 1292| Name | Type | Mandatory | Description | 1293| ----- | ----------------------------------- | ---- | ---------- | 1294| value | [RichEditorRange](#richeditorrange) | No | Source range. | 1295 1296**Return value** 1297 1298| Type | Description | 1299| ---------------------------------------- | ------- | 1300| Array<[RichEditorSpan](#richeditorspan12)> | Text and image span information. | 1301 1302### toStyledString<sup>12+</sup> 1303 1304toStyledString(value: RichEditorRange): StyledString 1305 1306Converts the component content within the given range into a styled string. 1307 1308**Atomic service API**: This API can be used in atomic services since API version 12. 1309 1310**System capability**: SystemCapability.ArkUI.ArkUI.Full 1311 1312**Parameters** 1313 1314| Name | Type | Mandatory | Description | 1315| ----- | ----------------------------------- | ---- | ---------- | 1316| value | [RichEditorRange](#richeditorrange) | No | Source range. | 1317 1318**Return value** 1319 1320| Type | Description | 1321| ---------------------------------------- | -------- | 1322| [StyledString](ts-universal-styled-string.md#styledstring) | Styled string after conversion. | 1323 1324## RichEditorStyledStringController<sup>12+</sup> 1325 1326Represents the controller of the **RichEditor** component constructed using the styled string. Inherits from [RichEditorBaseController](#richeditorbasecontroller12). 1327 1328### Objects to Import 1329 1330``` 1331controller: RichEditorStyledStringController = new RichEditorStyledStringController() 1332``` 1333 1334### getSelection<sup>12+</sup> 1335 1336getSelection(): RichEditorRange 1337 1338Obtains the current selection range of the **RichEditor** component. 1339 1340**Atomic service API**: This API can be used in atomic services since API version 12. 1341 1342**System capability**: SystemCapability.ArkUI.ArkUI.Full 1343 1344**Return value** 1345 1346| Type | Description | 1347| ---------------------------------------- | ------- | 1348| [RichEditorRange](#richeditorrange) | Selection range. | 1349 1350### setStyledString<sup>12+</sup> 1351 1352setStyledString(styledString: StyledString): void 1353 1354Sets the styled string displayed in the **RichEditor** component. 1355 1356**Atomic service API**: This API can be used in atomic services since API version 12. 1357 1358**System capability**: SystemCapability.ArkUI.ArkUI.Full 1359 1360**Parameters** 1361 1362| Name | Type | Mandatory | Description | 1363| ----- | ------ | ---- | ------------------- | 1364| value | [StyledString](ts-universal-styled-string.md#styledstring) | Yes | Styled string.<br>**NOTE**<br>The child class [MutableStyledString](ts-universal-styled-string.md#mutablestyledstring) of **StyledString** can also serve as the argument. | 1365 1366### getStyledString<sup>12+</sup> 1367 1368getStyledString(): MutableStyledString; 1369 1370Obtains the styled string displayed in the **RichEditor** component. 1371 1372**Atomic service API**: This API can be used in atomic services since API version 12. 1373 1374**System capability**: SystemCapability.ArkUI.ArkUI.Full 1375 1376**Return value** 1377 1378| Type | Description | 1379| ------- | ----------------------------- | 1380| [MutableStyledString](ts-universal-styled-string.md#mutablestyledstring) | Styled string displayed in the **RichEditor** component. | 1381 1382### onContentChanged<sup>12+</sup> 1383 1384onContentChanged(listener: StyledStringChangedListener): void 1385 1386Register a callback for text content changes, which will be invoked when the text content is changed by the backend program. 1387 1388**Atomic service API**: This API can be used in atomic services since API version 12. 1389 1390**System capability**: SystemCapability.ArkUI.ArkUI.Full 1391 1392**Parameters** 1393 1394| Name | Type | Mandatory | Description | 1395| ----- | ------ | ---- | ------------------- | 1396| listener | [StyledStringChangedListener](#styledstringchangedlistener12) | Yes | Callback listener for text content changes. | 1397 1398## RichEditorSelection 1399 1400Provides information about the selected content. 1401 1402**Atomic service API**: This API can be used in atomic services since API version 11. 1403 1404**System capability**: SystemCapability.ArkUI.ArkUI.Full 1405 1406| Name | Type | Mandatory | Description | 1407| --------- | ---------------------------------------- | ---- | ------- | 1408| selection | [number, number] | Yes | Range of the selected. | 1409| spans | Array<[RichEditorTextSpanResult](#richeditortextspanresult)\| [RichEditorImageSpanResult](#richeditorimagespanresult)> | Yes | Span information. | 1410 1411 1412## RichEditorUpdateTextSpanStyleOptions 1413 1414Defines the text span style options. 1415 1416**Atomic service API**: This API can be used in atomic services since API version 11. 1417 1418**System capability**: SystemCapability.ArkUI.ArkUI.Full 1419 1420| Name | Type | Mandatory | Description | 1421| --------- | ---------------------------------------- | ---- | ------------------------------- | 1422| start | number | No | Start position of the span whose style needs to be updated. If this parameter is left empty or set to a negative value, the value **0** will be used. | 1423| end | number | No | End position of the span whose style needs to be updated. If this parameter is left empty or set to a value beyond the range, it indicates infinity. | 1424| textStyle | [RichEditorTextStyle](#richeditortextstyle) | Yes | Text style. | 1425 1426> **NOTE** 1427> 1428> If the value of **start** is greater than that of **end**, the value **0** will be used as **start** and infinity as **end**. 1429 1430## RichEditorUpdateImageSpanStyleOptions 1431 1432Defines the image span style options. 1433 1434**Atomic service API**: This API can be used in atomic services since API version 11. 1435 1436**System capability**: SystemCapability.ArkUI.ArkUI.Full 1437 1438| Name | Type | Mandatory | Description | 1439| ---------- | ---------------------------------------- | ---- | ------------------------------- | 1440| start | number | No | Start position of the span whose style needs to be updated. If this parameter is left empty or set to a negative value, the value **0** will be used. | 1441| end | number | No | End position of the span whose style needs to be updated. If this parameter is left empty or set to a value beyond the range, it indicates infinity. | 1442| imageStyle | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | Yes | Image style. | 1443 1444> **NOTE** 1445> 1446> If the value of **start** is greater than that of **end**, the value **0** will be used as **start** and infinity as **end**. 1447 1448## RichEditorUpdateSymbolSpanStyleOptions<sup>11+</sup> 1449 1450Defines the symbol span style options. 1451 1452**Atomic service API**: This API can be used in atomic services since API version 12. 1453 1454**System capability**: SystemCapability.ArkUI.ArkUI.Full 1455 1456| Name | Type | Mandatory | Description | 1457| ----------- | ---------------------------------------- | ---- | ------------------------------- | 1458| start | number | No | Start position of the span whose style needs to be updated. If this parameter is left empty or set to a negative value, the value **0** will be used. | 1459| end | number | No | End position of the span whose style needs to be updated. If this parameter is left empty or set to a value beyond the range, it indicates infinity. | 1460| symbolStyle | [RichEditorSymbolSpanStyle](#richeditorsymbolspanstyle11) | Yes | Style of the symbol span. | 1461 1462> **NOTE** 1463> 1464> If the value of **start** is greater than that of **end**, the value **0** will be used as **start** and infinity as **end**. 1465 1466## RichEditorParagraphStyleOptions<sup>11+</sup> 1467 1468Describes the paragraph style options. 1469 1470**Atomic service API**: This API can be used in atomic services since API version 12. 1471 1472**System capability**: SystemCapability.ArkUI.ArkUI.Full 1473 1474| Name | Type | Mandatory | Description | 1475| ----- | ---------------------------------------- | ---- | ---------------------------------- | 1476| start | number | No | Start position of the paragraph whose style needs to be updated. If this parameter is left empty or set to a negative value, the value **0** will be used. | 1477| end | number | No | End position of the span whose style needs to be updated. If this parameter is left empty or set to a negative value or a value beyond the range, it indicates infinity. | 1478| style | [RichEditorParagraphStyle](#richeditorparagraphstyle11) | Yes | Paragraph style. | 1479 1480> **NOTE** 1481> 1482> Applicable scope of the API: spans involved in the specified range. 1483> If the value of **start** is greater than that of **end**, the value **0** will be used as **start** and infinity as **end**. 1484 1485 1486## RichEditorParagraphStyle<sup>11+</sup> 1487 1488Describes the paragraph style. 1489 1490**Atomic service API**: This API can be used in atomic services since API version 12. 1491 1492**System capability**: SystemCapability.ArkUI.ArkUI.Full 1493 1494| Name | Type | Mandatory | Description | 1495| ------------- | ---------------------------------------- | ---- | ------------------ | 1496| textAlign | [TextAlign](ts-appendix-enums.md#textalign) | No | Horizontal alignment mode of the text. <br>Default value: **TextAlign.START**<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 1497| leadingMargin | [Dimension](ts-types.md#dimension10) \| [LeadingMarginPlaceholder](#leadingmarginplaceholder11) | No | Indent of the paragraph. It has no effect if the paragraph starts with an image or builder span. If of the **Dimension** type, this parameter cannot be set in percentage. Default value: **{"size":["0.00px","0.00px"]}**<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 1498| wordBreak<sup>12+</sup> | [WordBreak](ts-appendix-enums.md#wordbreak11) | No | Word break rule.<br>Default value: **WordBreak.BREAK_WORD** | 1499| lineBreakStrategy<sup>12+</sup> | [LineBreakStrategy](ts-appendix-enums.md#linebreakstrategy12) | No | Line break rule.<br>Default value: **LineBreakStrategy.GREEDY**<br>This parameter takes effect when **wordBreak** is not set to **breakAll**. Hyphens are not supported. | 1500 1501## LeadingMarginPlaceholder<sup>11+</sup> 1502 1503Describes the leading margin placeholder, which dictates the distance between the left edges of the paragraph and the component. 1504 1505**System capability**: SystemCapability.ArkUI.ArkUI.Full 1506 1507| Name | Type | Mandatory | Description | 1508| -------- | ---------------------------------------- | ---- | -------------- | 1509| pixelMap | [PixelMap](../../apis-image-kit/js-apis-image.md#pixelmap7) | Yes | Image content.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1510| size | \[[Dimension](ts-types.md#dimension10), [Dimension](ts-types.md#dimension10)\] | Yes | Image size. This parameter cannot be set in percentage. | 1511 1512## RichEditorParagraphResult<sup>11+</sup> 1513 1514Describes the returned paragraph information. 1515 1516**Atomic service API**: This API can be used in atomic services since API version 12. 1517 1518**System capability**: SystemCapability.ArkUI.ArkUI.Full 1519 1520| Name | Type | Mandatory | Description | 1521| ----- | ---------------------------------------- | ---- | ------- | 1522| style | [RichEditorParagraphStyle](#richeditorparagraphstyle11) | Yes | Paragraph style. | 1523| range | \[number, number\] | Yes | Start and end positions of the paragraph. | 1524 1525## RichEditorTextSpanOptions 1526 1527Describes the options for adding a text span. 1528 1529**System capability**: SystemCapability.ArkUI.ArkUI.Full 1530 1531| Name | Type | Mandatory | Description | 1532| ---------------------------- | ---------------------------------------- | ---- | -------------------------- | 1533| offset | number | No | Position of the text span to be added. If this parameter is omitted, the paragraph is added to the end of all content.<br>If the value specified is less than 0, the paragraph is placed at the beginning of all content. If the value is greater than the length of all content, the paragraph is placed at the end of all content.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1534| style | [RichEditorTextStyle](#richeditortextstyle) | No | Style of the text span to be added. If this parameter is left empty, the default text style will be used.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1535| paragraphStyle<sup>11+</sup> | [RichEditorParagraphStyle](#richeditorparagraphstyle11) | No | Paragraph style.<br>**Atomic service API**: This API can be used in atomic services since API version 12. | 1536| gesture<sup>11+</sup> | [RichEditorGesture](#richeditorgesture11) | No | Behavior-triggered callback. If this parameter is left empty, only the default system behavior is supported.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 1537 1538## RichEditorTextStyle 1539 1540Provides the text style information. 1541 1542**System capability**: SystemCapability.ArkUI.ArkUI.Full 1543 1544| Name | Type | Mandatory | Description | 1545| ------------------------ | ---------------------------------------- | ---- | ---------------------------------------- | 1546| fontColor | [ResourceColor](ts-types.md#resourcecolor) | No | Font color.<br> Default value: **$r('sys.color.font_primary')**<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1547| fontSize | [Length](ts-types.md#length) \| number | No | Font size. If **Length** is of the number type, the unit fp is used. The default value is **16**. The value cannot be a percentage. If the font size is set to 0, the default font size is used.<br>**Widget capability**: This API can be used in ArkTS widgets since API version 9.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1548| fontStyle | [FontStyle](ts-appendix-enums.md#fontstyle) | No | Font style.<br>Default value: **FontStyle.Normal**<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1549| fontWeight | [FontWeight](ts-appendix-enums.md#fontweight) \| number \| string | No | Font weight.<br>For the number type, the value ranges from 100 to 900, at an interval of 100. A larger value indicates a heavier font weight. The default value is **400**.<br>For the string type, only strings of the number type are supported, for example, **"400"**, **"bold"**, **"bolder"**, **"lighter"**, **"regular"**, and **"medium"**, which correspond to the enumerated values in **FontWeight**.<br>Default value: **FontWeight.Normal**<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1550| fontFamily | [ResourceStr](ts-types.md#resourcestr) | No | Font family. The HarmonyOS Sans font and [register custom fonts](../js-apis-font.md) are supported.<br>Default font: **'HarmonyOS Sans'**<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1551| decoration | [DecorationStyleInterface](ts-universal-styled-string.md#decorationstyleinterface) | No | Style and color of the text decorative line.<br>Default value of **type**: **TextDecorationType.None**<br>Default value of **color**: same as the font color<br>Default value of **style**: **TextDecorationStyle.SOLID**<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1552| textShadow<sup>11+</sup> | [ShadowOptions](ts-universal-attributes-image-effect.md#shadowoptions) \| Array<[ShadowOptions](ts-universal-attributes-image-effect.md#shadowoptions)> | No | Text shadow. It supports input parameters in an array to implement multiple text shadows.<br>**NOTE**<br>Only the shadow blur radius, shadow color, and shadow offset can be set.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 1553| lineHeight<sup>12+</sup> | number \| string \| [Resource](ts-types.md#resource) | No |Text line height. If the value is less than or equal to 0, the line height is not limited and the font size is adaptive. If the value is of the number type, the unit fp is used. The value cannot be a percentage.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 1554| letterSpacing<sup>12+</sup> | number \| string | No | Letter spacing. If the value is negative, the text is compressed. A negative value too small may result in the text being compressed to 0 and no content being displayed. If the value is of the number type, the unit fp is used. The value cannot be a percentage.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 1555| fontFeature<sup>12+</sup> | string | No | Font feature, for example, monospaced digits. If this parameter is not set, monospaced digits are used as the default value. If invalid characters are set, the default value is retrained.<br>Format: normal \| \<feature-tag-value\><br>Syntax for \<feature-tag-value\>: \<string\> \[ \<integer\> \| on \| off ]<br>There can be multiple **\<feature-tag-value\>** values, which are separated by commas (,).<br>For example, the input format for monospaced clock fonts is "ss01" on.<br>For details about the supported font features, see [Font Feature List](ts-basic-components-text.md#fontfeature12).<br>Font features are advanced typographic features, such as ligatures and monospace, for OpenType fonts. They are typically used in custom fonts and require the support of the font itself.<br>For more information about the font features, see [Low-level font feature settings control: the font-feature-settings property](https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop) and [The Complete CSS Demo for OpenType Features](https://sparanoid.com/lab/opentype-features/).<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 1556 1557## PlaceholderStyle<sup>12+</sup> 1558 1559Defines the style of the placeholder text. 1560 1561**Atomic service API**: This API can be used in atomic services since API version 12. 1562 1563**System capability**: SystemCapability.ArkUI.ArkUI.Full 1564 1565| Name | Type | Mandatory | Description | 1566| ---------------------------- | ---------------------------------------- | ---- | -------------------------- | 1567| font | [Font](ts-types.md#font) | No | Style of the placeholder text.<br>The default value follows the theme.| 1568| fontColor | [ResourceColor](ts-types.md#resourcecolor) | No | Color of the placeholder text.<br>The default value follows the theme.| 1569 1570## RichEditorImageSpanOptions 1571 1572Defines the options for adding an image span. 1573 1574**System capability**: SystemCapability.ArkUI.ArkUI.Full 1575 1576| Name | Type | Mandatory | Description | 1577| --------------------- | ---------------------------------------- | ---- | -------------------------- | 1578| offset | number | No | Position of the image span to be added. If this parameter is omitted, the paragraph is added to the end of all content.<br>If the value specified is less than 0, the paragraph is placed at the beginning of all content. If the value is greater than the length of all content, the paragraph is placed at the end of all content.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1579| imageStyle | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | No | Image style. If this parameter is left empty, the default image style will be used.<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1580| gesture<sup>11+</sup> | [RichEditorGesture](#richeditorgesture11) | No | Behavior-triggered callback. If this parameter is left empty, only the default system behavior is supported.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 1581 1582## RichEditorImageSpanStyle 1583 1584Provides the image span style information. 1585 1586**System capability**: SystemCapability.ArkUI.ArkUI.Full 1587 1588| Name | Type | Mandatory | Description | 1589| ------------------------- | ---------------------------------------- | ---- | ---------------------------------------- | 1590| size | [[Dimension](ts-types.md#dimension10), [Dimension](ts-types.md#dimension10)] | No | Width and height of the image. Default value: varies by the value of **objectFit**. If the value of **objectFit** is **Cover**, the image height is the component height minus the top and bottom paddings, and the image width is the component width minus the left and right paddings.<br>**Atomic service API**: This API can be used in atomic services since API version 11. | 1591| verticalAlign | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | No | Vertical alignment mode of the image.<br>Default value: **ImageSpanAlignment.BASELINE**<br>**Atomic service API**: This API can be used in atomic services since API version 11.| 1592| objectFit | [ImageFit](ts-appendix-enums.md#imagefit) | No | Scale mode of the image.<br> Default value: **ImageFit.Cover**<br>**Atomic service API**: This API can be used in atomic services since API version 11. | 1593| layoutStyle<sup>11+</sup> | [RichEditorLayoutStyle](#richeditorlayoutstyle11) | No | Image layout style. Default value: **{"borderRadius":"","margin":""}**<br><br>**Atomic service API**: This API can be used in atomic services since API version 12. | 1594 1595## RichEditorSymbolSpanOptions<sup>11+</sup> 1596 1597Defines offset position for adding the symbol span and the symbol span style. 1598 1599**Atomic service API**: This API can be used in atomic services since API version 12. 1600 1601**System capability**: SystemCapability.ArkUI.ArkUI.Full 1602 1603| Name | Type | Mandatory | Description | 1604| ------ | ---------------------------------------- | ---- | -------------------------- | 1605| offset | number | No | Position of the symbol span to be added. If this parameter is omitted, the span is added to the end of all content.<br>If the value specified is less than 0, the paragraph is placed at the beginning of all content. If the value is greater than the length of all content, the paragraph is placed at the end of all content. | 1606| style | [RichEditorSymbolSpanStyle](#richeditorsymbolspanstyle11) | No | Style of the symbol span to be added. If this parameter is left empty, the default style will be used. | 1607 1608## RichEditorSymbolSpanStyle<sup>11+</sup> 1609 1610Provides the symbol span style information. 1611 1612**Atomic service API**: This API can be used in atomic services since API version 12. 1613 1614**System capability**: SystemCapability.ArkUI.ArkUI.Full 1615 1616| Name | Type | Mandatory | Description | 1617| ------ | -------- | ---- | -------------------------------------- | 1618| fontColor | Array\<[ResourceColor](ts-types.md#resourcecolor)\> | No | Color of the symbol span.<br> Default value: varies depending on the rendering strategy. | 1619| fontSize | number \| string \| [Resource](ts-types.md#resource) | No | Size of the symbol span. The default unit is fp.<br>The default value follows the theme. | 1620| fontWeight | [FontWeight](ts-appendix-enums.md#fontweight) \| number \| string | No | Font weight of the symbol span.<br>For the number type, the value ranges from 100 to 900, at an interval of 100. A larger value indicates a heavier font weight. The default value is **400**.<br>For the string type, only strings of the number type are supported, for example, **"400"**, **"bold"**, **"bolder"**, **"lighter"**, **"regular"**, and **"medium"**, which correspond to the enumerated values in **FontWeight**.<br>Default value: **FontWeight.Normal** | 1621| renderingStrategy | [SymbolRenderingStrategy](ts-appendix-enums.md#symbolrenderingstrategy11) | No | Rendering strategy of the symbol span.<br>Default value: **SymbolRenderingStrategy.SINGLE**<br>**NOTE**<br>For the resources referenced in **$r('sys.symbol.ohos_*')**, only **ohos_trash_circle**, **ohos_folder_badge_plus**, and **ohos_lungs** support the **MULTIPLE_COLOR** and **MULTIPLE_OPACITY** modes. | 1622| effectStrategy | [SymbolEffectStrategy](ts-appendix-enums.md#symboleffectstrategy11) | No | Effect strategy of the symbol span.<br>Default value: **SymbolEffectStrategy.NONE**<br>**NOTE**<br>For the resources referenced in **$r('sys.symbol.ohos_*')**, only **ohos_wifi** supports the hierarchical effect. | 1623 1624## RichEditorBuilderSpanOptions<sup>11+</sup> 1625 1626Defines the options for adding an image span. 1627 1628**Atomic service API**: This API can be used in atomic services since API version 12. 1629 1630**System capability**: SystemCapability.ArkUI.ArkUI.Full 1631 1632| Name | Type | Mandatory | Description | 1633| ------ | ------ | ---- | ------------------------------------- | 1634| offset | number | No | Position of the builder span to be added. If this parameter is omitted or set to an invalid value, the span is added to the end of all content. | 1635 1636## RichEditorSpan<sup>12+</sup> 1637 1638type RichEditorSpan = RichEditorTextStyleResult | RichEditorImageSpanResult 1639 1640Provides the span information of the **RichEditor** component. 1641 1642**Atomic service API**: This API can be used in atomic services since API version 11. 1643 1644**System capability**: SystemCapability.ArkUI.ArkUI.Full 1645 1646| Type | Description | 1647| ------ | ---------- | 1648| [RichEditorTextStyleResult](#richeditortextstyleresult) | Provides the text span style information returned by the backend. | 1649| [RichEditorImageSpanResult](#richeditorimagespanresult) | Provides the image information returned by the backend. | 1650 1651## RichEditorRange 1652 1653Provides the span range information. 1654 1655**Atomic service API**: This API can be used in atomic services since API version 11. 1656 1657**System capability**: SystemCapability.ArkUI.ArkUI.Full 1658 1659| Name | Type | Mandatory | Description | 1660| ----- | ------ | ---- | ---------------------- | 1661| start | number | No | Start position. If this parameter is left empty or set to a negative value, the value **0** will be used. | 1662| end | number | No | End position. If this parameter is left empty or set to a negative value or any value beyond the range, it indicates infinity. | 1663 1664## SelectionMenuOptions<sup>11+</sup> 1665 1666Provides the selection range information. 1667 1668**Atomic service API**: This API can be used in atomic services since API version 11. 1669 1670**System capability**: SystemCapability.ArkUI.ArkUI.Full 1671 1672| Name | Type | Mandatory | Description | 1673| ----------- | ---------- | ---- | ------------- | 1674| onAppear | [MenuOnAppearCallback<sup>12+</sup>](#menuonappearcallback12) | No | Callback invoked when the custom context menu on selection is displayed. | 1675| onDisappear | Callback\<void\> | No | Callback invoked when the custom context menu on selection is closed. | 1676 1677## PasteEvent<sup>11+</sup> 1678 1679Defines a custom paste event. 1680 1681**Atomic service API**: This API can be used in atomic services since API version 11. 1682 1683**System capability**: SystemCapability.ArkUI.ArkUI.Full 1684 1685| Name | Type | Mandatory | Description | 1686| -------------- | ----------- | ---- | ----------------------------- | 1687| preventDefault | Callback\<void\> | No | Prevents the default paste event. | 1688 1689## CutEvent<sup>12+</sup> 1690 1691Defines a custom cut event. 1692 1693**Atomic service API**: This API can be used in atomic services since API version 12. 1694 1695**System capability**: SystemCapability.ArkUI.ArkUI.Full 1696 1697| Name | Type | Mandatory | Description | 1698| -------------- | ----------- | ---- | ----------------------------- | 1699| preventDefault | Callback\<void\> | No | Prevents the default cut event. | 1700 1701## CopyEvent<sup>12+</sup> 1702 1703Defines a custom copy event. 1704 1705**Atomic service API**: This API can be used in atomic services since API version 12. 1706 1707**System capability**: SystemCapability.ArkUI.ArkUI.Full 1708 1709| Name | Type | Mandatory | Description | 1710| -------------- | ----------- | ---- | ----------------------------- | 1711| preventDefault | Callback\<void\> | No | Prevents the default copy event. | 1712 1713## RichEditorGesture<sup>11+</sup> 1714 1715Defines the behavior-triggered callbacks. 1716 1717**Atomic service API**: This API can be used in atomic services since API version 12. 1718 1719**System capability**: SystemCapability.ArkUI.ArkUI.Full 1720 1721| Name | Type | Mandatory | Description | 1722| ----------- | ---------- | ---- | ------------- | 1723| onClick | Callback\<[ClickEvent](ts-universal-events-click.md#clickevent)\> | No | [ClickEvent](ts-universal-events-click.md#clickevent) indicates a user click event.<br>Called when a click is complete.<br>In the case of a double-click, this API is called upon the first click.| 1724| onLongPress | Callback\<[GestureEvent](ts-gesture-settings.md#gestureevent)\> | No | [GestureEvent](ts-gesture-settings.md#gestureevent object description) indicates a long press event.<br>Called when a long press is complete. | 1725 1726## KeyboardOptions<sup>12+</sup> 1727 1728Whether to support keyboard avoidance. 1729 1730**System capability**: SystemCapability.ArkUI.ArkUI.Full 1731 1732| Name | Type | Mandatory | Description | 1733| --------------- | --------------- |---- | ------------------------------------ | 1734| supportAvoidance | boolean | No | Whether to support keyboard avoidance. The value **true** means to support keyboard avoidance, and **false** (default) means the opposite. | 1735 1736## SubmitCallback<sup>12+</sup> 1737 1738Represents the callback invoked when the Enter key on the soft keyboard is pressed. 1739 1740**Atomic service API**: This API can be used in atomic services since API version 12. 1741 1742**System capability**: SystemCapability.ArkUI.ArkUI.Full 1743 1744| Name | Type | Mandatory | Description | 1745| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- | 1746| enterKey | [EnterKeyType](ts-types.md#enterkeytype) | Yes | Type of the Enter key. For details, see **EnterKeyType**. | 1747| event | [SubmitEvent](ts-types.md#submitevent11) | Yes | Submit event, which provides a method to keep the text box in editing state. | 1748 1749## MenuOnAppearCallback<sup>12+</sup> 1750 1751Represents the callback invoked when the custom context menu on selection is displayed. 1752 1753**System capability**: SystemCapability.ArkUI.ArkUI.Full 1754 1755| Name | Type | Mandatory | Description | 1756| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- | 1757| start | number | Yes | Start position of the selected content. | 1758| end | number | Yes | End position of the selected content. | 1759 1760## PasteEventCallback<sup>12+</sup> 1761 1762Triggered when the paste is about to be completed.<br> 1763type PasteEventCallback = (event?: PasteEvent) => void 1764 1765**System capability**: SystemCapability.ArkUI.ArkUI.Full 1766 1767| Name | Type | Mandatory | Description | 1768| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- | 1769| event | [PasteEvent](#pasteevent11) | No | Defines the custom paste event. | 1770 1771## OnDidChangeCallback<sup>12+</sup> 1772 1773type OnDidChangeCallback = (rangeBefore: TextRange, rangeAfter: TextRange) => void 1774 1775Represents the callback invoked after text changes. 1776 1777**Parameters** 1778 1779| Name | Type | Mandatory | Description | 1780| -- | -- | -- | -- | 1781| rangeBefore | [TextRange](ts-text-common.md#textrange12) | Yes | Range of the text to be changed. | 1782| rangeAfter | [TextRange](ts-text-common.md#textrange12) | Yes | Range of the text added. | 1783 1784## StyledStringChangedListener<sup>12+</sup> 1785Defines the listener for changes of the styled string text content. 1786| Name | Type | Mandatory | Description | 1787| -- | -- | -- | -- | 1788| onWillChange | Callback<[StyledStringChangeValue](#styledstringchangevalue12), boolean> | No | Callback invoked when text is about to change. | 1789| onDidChange | [OnDidChangeCallback](#ondidchangecallback12) | No | Callback invoked when text is changed. | 1790 1791## StyledStringChangeValue<sup>12+</sup> 1792Describes the text changes of the styled string. 1793 1794| Name | Type | Mandatory | Description | 1795| -- | -- | -- | -- | 1796| range | [TextRange](ts-text-common.md#textrange12) | Yes | Range of the styled string to be replaced in the original string. | 1797| replacementString | [StyledString](ts-universal-styled-string.md#styledstring) | Yes | Styled string used for replacement. | 1798 1799 1800## PreviewText<sup>12+</sup> 1801 1802Preview text. 1803 1804**System capability**: SystemCapability.ArkUI.ArkUI.Full 1805 1806| Name | Type | Mandatory | Description | 1807| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- | 1808| offset | number | Yes | Start position of the preview text. | 1809| value | string | Yes | Content of the preview text. | 1810 1811## Example 1812 1813### Example 1 1814 1815```ts 1816// xxx.ets 1817@Entry 1818@Component 1819struct Index { 1820 controller: RichEditorController = new RichEditorController(); 1821 options: RichEditorOptions = { controller: this.controller }; 1822 private start: number = -1; 1823 private end: number = -1; 1824 @State message: string = "[-1, -1]" 1825 @State content: string = "" 1826 1827 build() { 1828 Column() { 1829 Column() { 1830 Text("selection range:").width("100%") 1831 Text() { 1832 Span(this.message) 1833 }.width("100%") 1834 Text("selection content:").width("100%") 1835 Text() { 1836 Span(this.content) 1837 }.width("100%") 1838 } 1839 .borderWidth(1) 1840 .borderColor(Color.Red) 1841 .width("100%") 1842 .height("20%") 1843 1844 Row() { 1845 Button ("Update Style: Bold").onClick(() => { 1846 this.controller.updateSpanStyle({ 1847 start: this.start, 1848 end: this.end, 1849 textStyle: 1850 { 1851 fontWeight: FontWeight.Bolder 1852 } 1853 }) 1854 }) 1855 Button("Obtain Selection").onClick(() => { 1856 this.content = ""; 1857 this.controller.getSpans({ 1858 start: this.start, 1859 end: this.end 1860 }).forEach(item => { 1861 if(typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined'){ 1862 this.content += (item as RichEditorImageSpanResult).valueResourceStr; 1863 this.content += "\n" 1864 } else { 1865 if(typeof(item as RichEditorTextSpanResult)['symbolSpanStyle'] != 'undefined') { 1866 this.content += (item as RichEditorTextSpanResult).symbolSpanStyle?.fontSize; 1867 this.content += "\n" 1868 }else { 1869 this.content += (item as RichEditorTextSpanResult).value; 1870 this.content += "\n" 1871 } 1872 } 1873 }) 1874 }) 1875 Button("Delete Selection").onClick(() => { 1876 this.controller.deleteSpans({ 1877 start: this.start, 1878 end: this.end 1879 }) 1880 this.start = -1; 1881 this.end = -1; 1882 this.message = "[" + this.start + ", " + this.end + "]" 1883 }) 1884 } 1885 .borderWidth(1) 1886 .borderColor(Color.Red) 1887 .width("100%") 1888 .height("10%") 1889 1890 Column() { 1891 RichEditor(this.options) 1892 .onReady(() => { 1893 this.controller.addTextSpan("012345", 1894 { 1895 style: 1896 { 1897 fontColor: Color.Orange, 1898 fontSize: 30 1899 } 1900 }) 1901 this.controller.addSymbolSpan($r("sys.symbol.ohos_trash"), 1902 { 1903 style: 1904 { 1905 fontSize: 30 1906 } 1907 }) 1908 this.controller.addImageSpan($r("app.media.icon"), 1909 { 1910 imageStyle: 1911 { 1912 size: ["57px", "57px"] 1913 } 1914 }) 1915 this.controller.addTextSpan("56789", 1916 { 1917 style: 1918 { 1919 fontColor: Color.Black, 1920 fontSize: 30 1921 } 1922 }) 1923 }) 1924 .onSelect((value: RichEditorSelection) => { 1925 this.start = value.selection[0]; 1926 this.end = value.selection[1]; 1927 this.message = "[" + this.start + ", " + this.end + "]" 1928 }) 1929 .aboutToIMEInput((value: RichEditorInsertValue) => { 1930 console.log("---------------------- aboutToIMEInput ----------------------") 1931 console.log("insertOffset:" + value.insertOffset) 1932 console.log("insertValue:" + value.insertValue) 1933 return true; 1934 }) 1935 .onIMEInputComplete((value: RichEditorTextSpanResult) => { 1936 console.log("---------------------- onIMEInputComplete ---------------------") 1937 console.log("spanIndex:" + value.spanPosition.spanIndex) 1938 console.log("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]") 1939 console.log("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]") 1940 console.log("value:" + value.value) 1941 }) 1942 .aboutToDelete((value: RichEditorDeleteValue) => { 1943 console.log("---------------------- aboutToDelete --------------------------") 1944 console.log("offset:" + value.offset) 1945 console.log("direction:" + value.direction) 1946 console.log("length:" + value.length) 1947 value.richEditorDeleteSpans.forEach(item => { 1948 console.log("---------------------- item --------------------------") 1949 console.log("spanIndex:" + item.spanPosition.spanIndex) 1950 console.log("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]") 1951 console.log("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]") 1952 if (typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') { 1953 console.log("image:" + (item as RichEditorImageSpanResult).valueResourceStr) 1954 } else { 1955 console.log("text:" + (item as RichEditorTextSpanResult).value) 1956 } 1957 }) 1958 return true; 1959 }) 1960 .onDeleteComplete(() => { 1961 console.log("---------------------- onDeleteComplete ------------------------") 1962 }) 1963 .placeholder("input...", { 1964 fontColor: Color.Gray, 1965 font: { 1966 size: 16, 1967 weight: FontWeight.Normal, 1968 family: "HarmonyOS Sans", 1969 style: FontStyle.Normal 1970 } 1971 }) 1972 .borderWidth(1) 1973 .borderColor(Color.Green) 1974 .width("100%") 1975 .height("30%") 1976 } 1977 .borderWidth(1) 1978 .borderColor(Color.Red) 1979 .width("100%") 1980 .height("70%") 1981 } 1982 } 1983} 1984``` 1985 1986 1987### Example 2 1988 1989```ts 1990// xxx.ets 1991@Entry 1992@Component 1993struct RichEditorExample { 1994 controller: RichEditorController = new RichEditorController() 1995 1996 // Create a custom keyboard component. 1997 @Builder CustomKeyboardBuilder() { 1998 Column() { 1999 Grid() { 2000 ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, '*', 0, '#'], (item: number | string) => { 2001 GridItem() { 2002 Button(item + "") 2003 .width(110).onClick(() => { 2004 this.controller.addTextSpan(item + '', { 2005 offset: this.controller.getCaretOffset(), 2006 style: 2007 { 2008 fontColor: Color.Orange, 2009 fontSize: 30 2010 } 2011 }) 2012 this.controller.setCaretOffset(this.controller.getCaretOffset() + item.toString().length) 2013 }) 2014 } 2015 }) 2016 }.maxCount(3).columnsGap(10).rowsGap(10).padding(5) 2017 }.backgroundColor(Color.Gray) 2018 } 2019 2020 build() { 2021 Column() { 2022 RichEditor({ controller: this.controller }) 2023 // Bind the custom keyboard. 2024 .customKeyboard(this.CustomKeyboardBuilder()).margin(10).border({ width: 1 }) 2025 .height(200) 2026 .borderWidth(1) 2027 .borderColor(Color.Red) 2028 .width("100%") 2029 } 2030 } 2031} 2032``` 2033 2034 2035 2036### Example 3 2037 2038```ts 2039// xxx.ets 2040import { BusinessError, pasteboard } from '@kit.BasicServicesKit'; 2041 2042export interface SelectionMenuTheme { 2043 imageSize: number; 2044 buttonSize: number; 2045 menuSpacing: number; 2046 editorOptionMargin: number; 2047 expandedOptionPadding: number; 2048 defaultMenuWidth: number; 2049 imageFillColor: Resource; 2050 backGroundColor: Resource; 2051 iconBorderRadius: Resource; 2052 containerBorderRadius: Resource; 2053 cutIcon: Resource; 2054 copyIcon: Resource; 2055 pasteIcon: Resource; 2056 selectAllIcon: Resource; 2057 shareIcon: Resource; 2058 translateIcon: Resource; 2059 searchIcon: Resource; 2060 arrowDownIcon: Resource; 2061 iconPanelShadowStyle: ShadowStyle; 2062 iconFocusBorderColor: Resource; 2063} 2064 2065export const defaultTheme: SelectionMenuTheme = { 2066 imageSize: 24, 2067 buttonSize: 48, 2068 menuSpacing: 8, 2069 editorOptionMargin: 1, 2070 expandedOptionPadding: 3, 2071 defaultMenuWidth: 256, 2072 imageFillColor: $r('sys.color.ohos_id_color_primary'), 2073 backGroundColor: $r('sys.color.ohos_id_color_dialog_bg'), 2074 iconBorderRadius: $r('sys.float.ohos_id_corner_radius_default_m'), 2075 containerBorderRadius: $r('sys.float.ohos_id_corner_radius_card'), 2076 cutIcon: $r("sys.media.ohos_ic_public_cut"), 2077 copyIcon: $r("sys.media.ohos_ic_public_copy"), 2078 pasteIcon: $r("sys.media.ohos_ic_public_paste"), 2079 selectAllIcon: $r("sys.media.ohos_ic_public_select_all"), 2080 shareIcon: $r("sys.media.ohos_ic_public_share"), 2081 translateIcon: $r("sys.media.ohos_ic_public_translate_c2e"), 2082 searchIcon: $r("sys.media.ohos_ic_public_search_filled"), 2083 arrowDownIcon: $r("sys.media.ohos_ic_public_arrow_down"), 2084 iconPanelShadowStyle: ShadowStyle.OUTER_DEFAULT_MD, 2085 iconFocusBorderColor: $r('sys.color.ohos_id_color_focused_outline'), 2086} 2087 2088@Entry 2089@Component 2090struct SelectionMenu { 2091 @State message: string = 'Hello World' 2092 @State textSize: number = 40 2093 @State sliderShow: boolean = false 2094 @State start: number = -1 2095 @State end: number = -1 2096 @State colorTransparent: Color = Color.Transparent 2097 controller: RichEditorController = new RichEditorController(); 2098 options: RichEditorOptions = { controller: this.controller } 2099 private iconArr: Array<Resource> = 2100 [$r('app.media.icon'), $r("app.media.icon"), $r('app.media.icon'), 2101 $r("app.media.icon"), $r('app.media.icon')] 2102 @State iconBgColor: ResourceColor[] = new Array(this.iconArr.length).fill(this.colorTransparent) 2103 @State pasteEnable: boolean = false 2104 @State visibilityValue: Visibility = Visibility.Visible 2105 @State textStyle: RichEditorTextStyle = {} 2106 private fontWeightTable: string[] = ["100", "200", "300", "400", "500", "600", "700", "800", "900", "bold", "normal", "bolder", "lighter", "medium", "regular"] 2107 private theme: SelectionMenuTheme = defaultTheme; 2108 2109 aboutToAppear() { 2110 if (this.controller) { 2111 let richEditorSelection = this.controller.getSelection() 2112 if (richEditorSelection) { 2113 let start = richEditorSelection.selection[0] 2114 let end = richEditorSelection.selection[1] 2115 if (start === 0 && this.controller.getSpans({ start: end + 1, end: end + 1 }).length === 0) { 2116 this.visibilityValue = Visibility.None 2117 } else { 2118 this.visibilityValue = Visibility.Visible 2119 } 2120 } 2121 } 2122 let sysBoard = pasteboard.getSystemPasteboard() 2123 if (sysBoard && sysBoard.hasDataSync()) { 2124 this.pasteEnable = true 2125 } else { 2126 this.pasteEnable = false 2127 } 2128 } 2129 2130 build() { 2131 Column() { 2132 Column() { 2133 RichEditor(this.options) 2134 .onReady(() => { 2135 this.controller.addTextSpan(this.message, { style: { fontColor: Color.Orange, fontSize: 30 } }) 2136 }) 2137 .onSelect((value: RichEditorSelection) => { 2138 if (value.selection[0] == -1 && value.selection[1] == -1) { 2139 return 2140 } 2141 this.start = value.selection[0] 2142 this.end = value.selection[1] 2143 }) 2144 .bindSelectionMenu(RichEditorSpanType.TEXT, this.panel, ResponseType.LongPress, { onDisappear: () => { 2145 this.sliderShow = false 2146 }}) 2147 .bindSelectionMenu(RichEditorSpanType.TEXT, this.panel, ResponseType.RightClick, { onDisappear: () => { 2148 this.sliderShow = false 2149 }}) 2150 .borderWidth(1) 2151 .borderColor(Color.Red) 2152 .width(200) 2153 .height(200) 2154 }.width('100%').backgroundColor(Color.White) 2155 }.height('100%') 2156 } 2157 2158 PushDataToPasteboard(richEditorSelection: RichEditorSelection) { 2159 let sysBoard = pasteboard.getSystemPasteboard() 2160 let pasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, '') 2161 if (richEditorSelection.spans && richEditorSelection.spans.length > 0) { 2162 let count = richEditorSelection.spans.length 2163 for (let i = count - 1; i >= 0; i--) { 2164 let item = richEditorSelection.spans[i] 2165 if ((item as RichEditorTextSpanResult)?.textStyle) { 2166 let span = item as RichEditorTextSpanResult 2167 let style = span.textStyle 2168 let data = pasteboard.createRecord(pasteboard.MIMETYPE_TEXT_PLAIN, span.value.substring(span.offsetInSpan[0], span.offsetInSpan[1])) 2169 let prop = pasteData.getProperty() 2170 let temp: Record<string, Object> = { 2171 'color': style.fontColor, 2172 'size': style.fontSize, 2173 'style': style.fontStyle, 2174 'weight': this.fontWeightTable[style.fontWeight], 2175 'fontFamily': style.fontFamily, 2176 'decorationType': style.decoration.type, 2177 'decorationColor': style.decoration.color 2178 } 2179 prop.additions[i] = temp; 2180 pasteData.addRecord(data) 2181 pasteData.setProperty(prop) 2182 } 2183 } 2184 } 2185 sysBoard.clearData() 2186 sysBoard.setData(pasteData).then(() => { 2187 console.info('SelectionMenu copy option, Succeeded in setting PasteData.'); 2188 this.pasteEnable = true; 2189 }).catch((err: BusinessError) => { 2190 console.error('SelectionMenu copy option, Failed to set PasteData. Cause:' + err.message); 2191 }) 2192 } 2193 2194 PopDataFromPasteboard(richEditorSelection: RichEditorSelection) { 2195 let start = richEditorSelection.selection[0] 2196 let end = richEditorSelection.selection[1] 2197 if (start == end && this.controller) { 2198 start = this.controller.getCaretOffset() 2199 end = this.controller.getCaretOffset() 2200 } 2201 let moveOffset = 0 2202 let sysBoard = pasteboard.getSystemPasteboard() 2203 sysBoard.getData((err, data) => { 2204 if (err) { 2205 return 2206 } 2207 let count = data.getRecordCount() 2208 for (let i = 0; i < count; i++) { 2209 const element = data.getRecord(i); 2210 let tex: RichEditorTextStyle = { 2211 fontSize: 16, 2212 fontColor: Color.Black, 2213 fontWeight: FontWeight.Normal, 2214 fontFamily: "HarmonyOS Sans", 2215 fontStyle: FontStyle.Normal, 2216 decoration: { type: TextDecorationType.None, color: "#FF000000", style: TextDecorationStyle.SOLID } 2217 } 2218 if (data.getProperty() && data.getProperty().additions[i]) { 2219 const tmp = data.getProperty().additions[i] as Record<string, Object | undefined>; 2220 if (tmp.color) { 2221 tex.fontColor = tmp.color as ResourceColor; 2222 } 2223 if (tmp.size) { 2224 tex.fontSize = tmp.size as Length | number; 2225 } 2226 if (tmp.style) { 2227 tex.fontStyle = tmp.style as FontStyle; 2228 } 2229 if (tmp.weight) { 2230 tex.fontWeight = tmp.weight as number | FontWeight | string; 2231 } 2232 if (tmp.fontFamily) { 2233 tex.fontFamily = tmp.fontFamily as ResourceStr; 2234 } 2235 if (tmp.decorationType && tex.decoration) { 2236 tex.decoration.type = tmp.decorationType as TextDecorationType; 2237 } 2238 if (tmp.decorationColor && tex.decoration) { 2239 tex.decoration.color = tmp.decorationColor as ResourceColor; 2240 } 2241 if (tex.decoration) { 2242 tex.decoration = { type: tex.decoration.type, color: tex.decoration.color } 2243 } 2244 } 2245 if (element && element.plainText && element.mimeType === pasteboard.MIMETYPE_TEXT_PLAIN && this.controller) { 2246 this.controller.addTextSpan(element.plainText, 2247 { 2248 style: tex, 2249 offset: start + moveOffset 2250 } 2251 ) 2252 moveOffset += element.plainText.length 2253 } 2254 } 2255 if (this.controller) { 2256 this.controller.setCaretOffset(start + moveOffset) 2257 this.controller.closeSelectionMenu() 2258 } 2259 if (start != end && this.controller) { 2260 this.controller.deleteSpans({ start: start + moveOffset, end: end + moveOffset }) 2261 } 2262 }) 2263 } 2264 2265 @Builder 2266 panel() { 2267 Column() { 2268 this.iconPanel() 2269 if (!this.sliderShow) { 2270 this.SystemMenu() 2271 } else { 2272 this.sliderPanel() 2273 } 2274 }.width(256) 2275 } 2276 2277 @Builder iconPanel() { 2278 Column() { 2279 Row({ space: 2 }) { 2280 ForEach(this.iconArr, (item:Resource, index ?: number) => { 2281 Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 2282 Image(item).fillColor(this.theme.imageFillColor).width(24).height(24).focusable(true).draggable(false) 2283 } 2284 .borderRadius(this.theme.iconBorderRadius) 2285 .width(this.theme.buttonSize) 2286 .height(this.theme.buttonSize) 2287 .onClick(() => { 2288 if (index as number == 0) { 2289 this.sliderShow = false 2290 if (this.controller) { 2291 let selection = this.controller.getSelection(); 2292 let spans = selection.spans 2293 spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { 2294 if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { 2295 let span = item as RichEditorTextSpanResult 2296 this.textStyle = span.textStyle 2297 let start = span.offsetInSpan[0] 2298 let end = span.offsetInSpan[1] 2299 let offset = span.spanPosition.spanRange[0] 2300 if (this.textStyle.fontWeight != 11) { 2301 this.textStyle.fontWeight = FontWeight.Bolder 2302 } else { 2303 this.textStyle.fontWeight = FontWeight.Normal 2304 } 2305 this.controller.updateSpanStyle({ 2306 start: offset + start, 2307 end: offset + end, 2308 textStyle: this.textStyle 2309 }) 2310 } 2311 }) 2312 } 2313 } else if (index as number == 1) { 2314 this.sliderShow = false 2315 if (this.controller) { 2316 let selection = this.controller.getSelection(); 2317 let spans = selection.spans 2318 spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { 2319 if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { 2320 let span = item as RichEditorTextSpanResult 2321 this.textStyle = span.textStyle 2322 let start = span.offsetInSpan[0] 2323 let end = span.offsetInSpan[1] 2324 let offset = span.spanPosition.spanRange[0] 2325 if (this.textStyle.fontStyle == FontStyle.Italic) { 2326 this.textStyle.fontStyle = FontStyle.Normal 2327 } else { 2328 this.textStyle.fontStyle = FontStyle.Italic 2329 } 2330 this.controller.updateSpanStyle({ 2331 start: offset + start, 2332 end: offset + end, 2333 textStyle: this.textStyle 2334 }) 2335 } 2336 }) 2337 } 2338 } else if (index as number == 2) { 2339 this.sliderShow = false 2340 if (this.controller) { 2341 let selection = this.controller.getSelection(); 2342 let spans = selection.spans 2343 spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { 2344 if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { 2345 let span = item as RichEditorTextSpanResult 2346 this.textStyle = span.textStyle 2347 let start = span.offsetInSpan[0] 2348 let end = span.offsetInSpan[1] 2349 let offset = span.spanPosition.spanRange[0] 2350 if (this.textStyle.decoration) { 2351 if (this.textStyle.decoration.type == TextDecorationType.Underline) { 2352 this.textStyle.decoration.type = TextDecorationType.None 2353 } else { 2354 this.textStyle.decoration.type = TextDecorationType.Underline 2355 } 2356 } else { 2357 this.textStyle.decoration = { type: TextDecorationType.Underline, color: Color.Black, style: TextDecorationStyle.SOLID } 2358 } 2359 this.controller.updateSpanStyle({ 2360 start: offset + start, 2361 end: offset + end, 2362 textStyle: this.textStyle 2363 }) 2364 } 2365 }) 2366 } 2367 } else if (index as number == 3) { 2368 this.sliderShow = !this.sliderShow 2369 } else if (index as number == 4) { 2370 this.sliderShow = false 2371 if (this.controller) { 2372 let selection = this.controller.getSelection(); 2373 let spans = selection.spans 2374 spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { 2375 if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { 2376 let span = item as RichEditorTextSpanResult 2377 this.textStyle = span.textStyle 2378 let start = span.offsetInSpan[0] 2379 let end = span.offsetInSpan[1] 2380 let offset = span.spanPosition.spanRange[0] 2381 if (this.textStyle.fontColor == Color.Orange || this.textStyle.fontColor == '#FFFFA500') { 2382 this.textStyle.fontColor = Color.Black 2383 } else { 2384 this.textStyle.fontColor = Color.Orange 2385 } 2386 this.controller.updateSpanStyle({ 2387 start: offset + start, 2388 end: offset + end, 2389 textStyle: this.textStyle 2390 }) 2391 } 2392 }) 2393 } 2394 } 2395 }) 2396 .onTouch((event?: TouchEvent | undefined) => { 2397 if(event != undefined){ 2398 if (event.type === TouchType.Down) { 2399 this.iconBgColor[index as number] = $r('sys.color.ohos_id_color_click_effect') 2400 } 2401 if (event.type === TouchType.Up) { 2402 this.iconBgColor[index as number] = this.colorTransparent 2403 } 2404 } 2405 }) 2406 .onHover((isHover?: boolean, event?: HoverEvent) => { 2407 this.iconBgColor.forEach((icon:ResourceColor, index1) => { 2408 this.iconBgColor[index1] = this.colorTransparent 2409 }) 2410 if(isHover != undefined) { 2411 this.iconBgColor[index as number] = $r('sys.color.ohos_id_color_hover') 2412 } 2413 }) 2414 .backgroundColor(this.iconBgColor[index as number]) 2415 }) 2416 } 2417 } 2418 .clip(true) 2419 .width(this.theme.defaultMenuWidth) 2420 .padding(this.theme.expandedOptionPadding) 2421 .borderRadius(this.theme.containerBorderRadius) 2422 .margin({ bottom: this.theme.menuSpacing }) 2423 .backgroundColor(this.theme.backGroundColor) 2424 .shadow(this.theme.iconPanelShadowStyle) 2425 } 2426 2427 @Builder 2428 SystemMenu() { 2429 Column() { 2430 Menu() { 2431 if (this.controller) { 2432 MenuItemGroup() { 2433 MenuItem({ startIcon: this.theme.cutIcon, content: "Cut", labelInfo: "Ctrl+X" }) 2434 .onClick(() => { 2435 if (!this.controller) { 2436 return 2437 } 2438 let richEditorSelection = this.controller.getSelection() 2439 this.PushDataToPasteboard(richEditorSelection); 2440 this.controller.deleteSpans({ 2441 start: richEditorSelection.selection[0], 2442 end: richEditorSelection.selection[1] 2443 }) 2444 }) 2445 MenuItem({ startIcon: this.theme.copyIcon, content: "Copy", labelInfo: "Ctrl+C" }) 2446 .onClick(() => { 2447 if (!this.controller) { 2448 return 2449 } 2450 let richEditorSelection = this.controller.getSelection() 2451 this.PushDataToPasteboard(richEditorSelection); 2452 this.controller.closeSelectionMenu() 2453 }) 2454 MenuItem({ startIcon: this.theme.pasteIcon, content: "Paste", labelInfo: "Ctrl+V" }) 2455 .enabled(this.pasteEnable) 2456 .onClick(() => { 2457 if (!this.controller) { 2458 return 2459 } 2460 let richEditorSelection = this.controller.getSelection() 2461 this.PopDataFromPasteboard(richEditorSelection) 2462 }) 2463 MenuItem({ startIcon: this.theme.selectAllIcon, content: "Select all", labelInfo: "Ctrl+A" }) 2464 .visibility(this.visibilityValue) 2465 .onClick(() => { 2466 if (!this.controller) { 2467 return 2468 } 2469 this.controller.setSelection(-1, -1) 2470 this.visibilityValue = Visibility.None 2471 }) 2472 MenuItem({ startIcon: this.theme.shareIcon, content: "Share", labelInfo: "" }) 2473 .enabled(false) 2474 MenuItem({ startIcon: this.theme.translateIcon, content: "Translate", labelInfo: "" }) 2475 .enabled(false) 2476 MenuItem({ startIcon: this.theme.searchIcon, content: "Search", labelInfo: "" }) 2477 .enabled(false) 2478 } 2479 } 2480 } 2481 .onVisibleAreaChange([0.0, 1.0], () => { 2482 if (!this.controller) { 2483 return 2484 } 2485 let richEditorSelection = this.controller.getSelection() 2486 let start = richEditorSelection.selection[0] 2487 let end = richEditorSelection.selection[1] 2488 if (start === 0 && this.controller.getSpans({ start: end + 1, end: end + 1 }).length === 0) { 2489 this.visibilityValue = Visibility.None 2490 } else { 2491 this.visibilityValue = Visibility.Visible 2492 } 2493 }) 2494 .radius(this.theme.containerBorderRadius) 2495 .clip(true) 2496 .backgroundColor(Color.White) 2497 .width(this.theme.defaultMenuWidth) 2498 } 2499 .width(this.theme.defaultMenuWidth) 2500 } 2501 2502 @Builder sliderPanel() { 2503 Column() { 2504 Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) { 2505 Text('A').fontSize(15) 2506 Slider({ value: this.textSize, step: 10, style: SliderStyle.InSet }) 2507 .width(210) 2508 .onChange((value: number, mode: SliderChangeMode) => { 2509 if (this.controller) { 2510 let selection = this.controller.getSelection(); 2511 if (mode == SliderChangeMode.End) { 2512 if (this.textSize == undefined) { 2513 this.textSize = 0 2514 } 2515 let spans = selection.spans 2516 spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { 2517 if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { 2518 this.textSize = Math.max(this.textSize, (item as RichEditorTextSpanResult).textStyle.fontSize) 2519 } 2520 }) 2521 } 2522 if (mode == SliderChangeMode.Moving || mode == SliderChangeMode.Click) { 2523 this.start = selection.selection[0] 2524 this.end = selection.selection[1] 2525 this.textSize = value 2526 this.controller.updateSpanStyle({ 2527 start: this.start, 2528 end: this.end, 2529 textStyle: { fontSize: this.textSize } 2530 }) 2531 } 2532 } 2533 }) 2534 Text('A').fontSize(20).fontWeight(FontWeight.Medium) 2535 }.borderRadius(this.theme.containerBorderRadius) 2536 } 2537 .shadow(ShadowStyle.OUTER_DEFAULT_MD) 2538 .backgroundColor(Color.White) 2539 .borderRadius(this.theme.containerBorderRadius) 2540 .padding(15) 2541 .height(48) 2542 } 2543} 2544``` 2545> **NOTE** 2546> 2547> Icons in bold and italics are not preset in the system. The sample code uses the default icons. You need to replace the icons in **iconArr** with the desired icons. 2548 2549 2550 2551### Example 4 2552 2553```ts 2554// xxx.ets 2555@Entry 2556@Component 2557struct Index { 2558 controller: RichEditorController = new RichEditorController(); 2559 options: RichEditorOptions = { controller: this.controller }; 2560 private start: number = -1; 2561 private end: number = -1; 2562 @State message: string = "[-1, -1]" 2563 @State content: string = "" 2564 @State paddingVal: number = 5 2565 @State borderRad: number = 4 2566 2567 build() { 2568 Column() { 2569 Column() { 2570 Text("selection range:").width("100%") 2571 Text() { 2572 Span(this.message) 2573 }.width("100%") 2574 Text("selection content:").width("100%") 2575 Text() { 2576 Span(this.content) 2577 }.width("100%") 2578 } 2579 .borderWidth(1) 2580 .borderColor(Color.Red) 2581 .width("100%") 2582 .height("20%") 2583 2584 Row() { 2585 Button("updateSpanStyle1") 2586 .fontSize(12) 2587 .onClick(() => { 2588 this.controller.updateSpanStyle({ 2589 start: this.start, 2590 textStyle: 2591 { 2592 fontWeight: FontWeight.Bolder 2593 }, 2594 imageStyle: { 2595 size: ["80px", "80px"], 2596 layoutStyle: { 2597 borderRadius: undefined, 2598 margin: undefined 2599 } 2600 } 2601 }) 2602 }) 2603 2604 Button("updateSpanStyle2") 2605 .fontSize(12) 2606 .onClick(() => { 2607 this.controller.updateSpanStyle({ 2608 start: this.start, 2609 textStyle: 2610 { 2611 fontWeight: FontWeight.Bolder 2612 }, 2613 imageStyle: { 2614 size: ["70px", "70px"], 2615 layoutStyle: { 2616 borderRadius: { topLeft: '100px', topRight: '20px', bottomLeft: '100px', bottomRight: '20px' }, 2617 margin: { left: '30px', top: '20px', right: '20px', bottom: '20px' } 2618 } 2619 } 2620 }) 2621 }) 2622 2623 Button("updateSpanStyle3") 2624 .fontSize(12) 2625 .onClick(() => { 2626 this.controller.updateSpanStyle({ 2627 start: this.start, 2628 textStyle: 2629 { 2630 fontWeight: FontWeight.Bolder 2631 }, 2632 imageStyle: { 2633 size: ["60px", "60px"], 2634 layoutStyle: { 2635 borderRadius: '-10px', 2636 margin: '-10px' 2637 } 2638 } 2639 }) 2640 }) 2641 } 2642 .borderWidth(1) 2643 .borderColor(Color.Red) 2644 .width("100%") 2645 .height("10%") 2646 2647 Row() { 2648 Button('addImageSpan1') 2649 .fontSize(12) 2650 .onClick(() => { 2651 this.controller.addImageSpan($r('app.media.app_icon'), { 2652 imageStyle: { 2653 size: ["80px", "80px"], 2654 layoutStyle: { 2655 borderRadius: '50px', 2656 margin: '40px' 2657 } 2658 } 2659 }) 2660 }) 2661 2662 Button('addImageSpan2') 2663 .fontSize(12) 2664 .onClick(() => { 2665 this.controller.addImageSpan($r('app.media.app_icon'), { 2666 imageStyle: { 2667 size: ["100px", "100px"], 2668 verticalAlign: ImageSpanAlignment.BOTTOM, 2669 layoutStyle: { 2670 borderRadius: undefined, 2671 margin: undefined 2672 } 2673 } 2674 }) 2675 }) 2676 2677 Button('addImageSpan3') 2678 .fontSize(12) 2679 .onClick(() => { 2680 this.controller.addImageSpan($r('app.media.app_icon'), { 2681 imageStyle: { 2682 size: ["60px", "60px"], 2683 verticalAlign: ImageSpanAlignment.BOTTOM, 2684 layoutStyle: { 2685 borderRadius: { topLeft: '10px', topRight: '20px', bottomLeft: '30px', bottomRight: '40px' }, 2686 margin: { left: '10px', top: '20px', right: '30px', bottom: '40px' } 2687 } 2688 } 2689 }) 2690 }) 2691 } 2692 .borderWidth(1) 2693 .borderColor(Color.Red) 2694 .width("100%") 2695 .height("10%") 2696 2697 Column() { 2698 RichEditor(this.options) 2699 .onReady(() => { 2700 this.controller.addTextSpan("0123456789", 2701 { 2702 style: 2703 { 2704 fontColor: Color.Orange, 2705 fontSize: 30 2706 } 2707 }) 2708 2709 this.controller.addImageSpan($r("app.media.app_icon"), 2710 { 2711 imageStyle: 2712 { 2713 size: ["60px", "60px"], 2714 verticalAlign: ImageSpanAlignment.BOTTOM, 2715 layoutStyle: { 2716 borderRadius: { topLeft: '10px', topRight: '20px', bottomLeft: '30px', bottomRight: '40px' }, 2717 margin: { left: '10px', top: '20px', right: '30px', bottom: '40px' } 2718 } 2719 } 2720 }) 2721 2722 this.controller.addTextSpan("0123456789", 2723 { 2724 style: 2725 { 2726 fontColor: Color.Black, 2727 fontSize: 30 2728 } 2729 }) 2730 }) 2731 .onSelect((value: RichEditorSelection) => { 2732 this.start = value.selection[0]; 2733 this.end = value.selection[1]; 2734 this.message = "[" + this.start + ", " + this.end + "]" 2735 }) 2736 .aboutToIMEInput((value: RichEditorInsertValue) => { 2737 console.log("---------------------- aboutToIMEInput ----------------------") 2738 console.log("insertOffset:" + value.insertOffset) 2739 console.log("insertValue:" + value.insertValue) 2740 return true; 2741 }) 2742 .onIMEInputComplete((value: RichEditorTextSpanResult) => { 2743 console.log("---------------------- onIMEInputComplete ---------------------") 2744 console.log("spanIndex:" + value.spanPosition.spanIndex) 2745 console.log("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]") 2746 console.log("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]") 2747 console.log("value:" + value.value) 2748 }) 2749 .aboutToDelete((value: RichEditorDeleteValue) => { 2750 console.log("---------------------- aboutToDelete --------------------------") 2751 console.log("offset:" + value.offset) 2752 console.log("direction:" + value.direction) 2753 console.log("length:" + value.length) 2754 value.richEditorDeleteSpans.forEach(item => { 2755 console.log("---------------------- item --------------------------") 2756 console.log("spanIndex:" + item.spanPosition.spanIndex) 2757 console.log("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]") 2758 console.log("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]") 2759 if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') { 2760 console.log("image:" + (item as RichEditorImageSpanResult).valueResourceStr) 2761 } else { 2762 console.log("text:" + (item as RichEditorTextSpanResult).value) 2763 } 2764 }) 2765 return true; 2766 }) 2767 .onDeleteComplete(() => { 2768 console.log("---------------------- onDeleteComplete ------------------------") 2769 }) 2770 .borderWidth(1) 2771 .borderColor(Color.Green) 2772 .width("100%") 2773 .height('80.00%') 2774 } 2775 .borderWidth(1) 2776 .borderColor(Color.Red) 2777 .width("100%") 2778 .height("70%") 2779 } 2780 } 2781} 2782``` 2783 2784 2785### Example 5 2786 2787```ts 2788// xxx.ets 2789@Entry 2790@Component 2791struct Index { 2792 controller: RichEditorController = new RichEditorController() 2793 options: RichEditorOptions = { controller: this.controller }; 2794 @State textFlag: string = "TextFlag"; 2795 2796 build() { 2797 Column() { 2798 Column() { 2799 Text(this.textFlag) 2800 .copyOption(CopyOptions.InApp) 2801 .fontSize(50) 2802 } 2803 Divider() 2804 Column() { 2805 RichEditor(this.options) 2806 .onReady(() => { 2807 this.controller.addTextSpan('Area1\n', { 2808 style: 2809 { 2810 fontColor: Color.Orange, 2811 fontSize: 50 2812 }, 2813 gesture: 2814 { 2815 onClick: () => { 2816 this.textFlag = "Area1 is onClick." 2817 }, 2818 onLongPress: () => { 2819 this.textFlag = "Area1 is onLongPress." 2820 } 2821 } 2822 }) 2823 2824 this.controller.addTextSpan('Area2\n', { 2825 style: 2826 { 2827 fontColor: Color.Blue, 2828 fontSize: 50 2829 }, 2830 gesture: 2831 { 2832 onClick: () => { 2833 this.textFlag = "Area2 is onClick." 2834 }, 2835 onLongPress: () => { 2836 this.textFlag = "Area2 is onLongPress." 2837 } 2838 } 2839 }) 2840 2841 this.controller.addImageSpan($r("app.media.icon"), 2842 { 2843 imageStyle: 2844 { 2845 size: ["100px", "100px"], 2846 layoutStyle: { 2847 margin: 5, 2848 borderRadius: 15 2849 } 2850 }, 2851 gesture: 2852 { 2853 onClick: () => { 2854 this.textFlag = "ImageSpan is onClick." 2855 }, 2856 onLongPress: () => { 2857 this.textFlag = "ImageSpan is onLongPress." 2858 } 2859 } 2860 }) 2861 }) 2862 } 2863 .borderWidth(1) 2864 .borderColor(Color.Red) 2865 .width("100%") 2866 .height("70%") 2867 } 2868 } 2869} 2870``` 2871 2872 2873### Example 6 2874 2875```ts 2876// xxx.ets 2877@Entry 2878@Component 2879struct Index { 2880 controller: RichEditorController = new RichEditorController(); 2881 private spanParagraphs: RichEditorParagraphResult[] = []; 2882 2883 build() { 2884 Column() { 2885 RichEditor({ controller: this.controller }) 2886 .onReady(() => { 2887 this.controller.addTextSpan("0123456789\n", { 2888 style: { 2889 fontColor: Color.Pink, 2890 fontSize: "32", 2891 }, 2892 paragraphStyle: { 2893 textAlign: TextAlign.Start, 2894 leadingMargin: 16 2895 } 2896 }) 2897 this.controller.addTextSpan("0123456789") 2898 }) 2899 .width("80%") 2900 .height("30%") 2901 .border({ width: 1, radius: 5 }) 2902 .draggable(false) 2903 2904 Column({ space: 5 }) { 2905 Button ("Align left").onClick () => { 2906 this.controller.updateParagraphStyle({ start: -1, end: -1, 2907 style: { 2908 textAlign: TextAlign.Start, 2909 } 2910 }) 2911 }) 2912 2913 Button ("Align right").onClick(() => { 2914 this.controller.updateParagraphStyle({ start: -1, end: -1, 2915 style: { 2916 textAlign: TextAlign.End, 2917 } 2918 }) 2919 }) 2920 2921 Button ("Center").onClick ((). => { 2922 this.controller.updateParagraphStyle({ start: -1, end: -1, 2923 style: { 2924 textAlign: TextAlign.Center, 2925 } 2926 }) 2927 }) 2928 Divider() 2929 Button("getParagraphs").onClick(() => { 2930 this.spanParagraphs = this.controller.getParagraphs({ start: -1, end: -1 }) 2931 console.log("RichEditor getParagraphs:" + JSON.stringify(this.spanParagraphs)) 2932 }) 2933 2934 Button("UpdateSpanStyle1").onClick(() => { 2935 this.controller.updateSpanStyle({ start: -1, end: -1, 2936 textStyle: { 2937 fontColor: Color.Brown, 2938 fontSize: 20 2939 } 2940 }) 2941 }) 2942 2943 Button("UpdateSpanStyle2").onClick(() => { 2944 this.controller.updateSpanStyle({ start: -1, end: -1, 2945 textStyle: { 2946 fontColor: Color.Green, 2947 fontSize: 30 2948 } 2949 }) 2950 }) 2951 } 2952 } 2953 } 2954} 2955``` 2956 2957 2958### Example 7 2959 2960```ts 2961// xxx.ets 2962import { font } from '@kit.ArkUI' 2963 2964const canvasWidth = 1000 2965const canvasHeight = 100 2966const Indentation = 40 2967class LeadingMarginCreator { 2968 private settings: RenderingContextSettings = new RenderingContextSettings(true) 2969 private offscreenCanvas: OffscreenCanvas = new OffscreenCanvas(canvasWidth, canvasHeight) 2970 private offContext: OffscreenCanvasRenderingContext2D = this.offscreenCanvas.getContext("2d", this.settings) 2971 public static instance: LeadingMarginCreator = new LeadingMarginCreator() 2972 2973 // Obtain the font size level, which ranges from 0 to 4. 2974 public getFontSizeLevel(fontSize: number) { 2975 const fontScaled: number = Number(fontSize) / 16 2976 2977 enum FontSizeScaleThreshold { 2978 SMALL = 0.9, 2979 NORMAL = 1.1, 2980 LEVEL_1_LARGE = 1.2, 2981 LEVEL_2_LARGE = 1.4, 2982 LEVEL_3_LARGE = 1.5 2983 } 2984 2985 let fontSizeLevel: number = 1 2986 2987 if (fontScaled < FontSizeScaleThreshold.SMALL) { 2988 fontSizeLevel = 0 2989 } else if (fontScaled < FontSizeScaleThreshold.NORMAL) { 2990 fontSizeLevel = 1 2991 } else if (fontScaled < FontSizeScaleThreshold.LEVEL_1_LARGE) { 2992 fontSizeLevel = 2 2993 } else if (fontScaled < FontSizeScaleThreshold.LEVEL_2_LARGE) { 2994 fontSizeLevel = 3 2995 } else if (fontScaled < FontSizeScaleThreshold.LEVEL_3_LARGE) { 2996 fontSizeLevel = 4 2997 } else { 2998 fontSizeLevel = 1 2999 } 3000 3001 return fontSizeLevel 3002 } 3003 // Obtain the font size level, which ranges from 0 to 4. 3004 public getmarginLevel(Width: number) { 3005 let marginlevel: number = 1 3006 if (Width == 40) { 3007 marginlevel = 2.0 3008 } else if (Width == 80) { 3009 marginlevel = 1.0 3010 } else if (Width == 120) { 3011 marginlevel = 2/3 3012 } else if (Width == 160) { 3013 marginlevel = 0.5 3014 } else if (Width == 200) { 3015 marginlevel = 0.4 3016 } 3017 return marginlevel 3018 } 3019 3020 public genStrMark(fontSize: number, str: string): PixelMap { 3021 this.offContext = this.offscreenCanvas.getContext("2d", this.settings) 3022 this.clearCanvas() 3023 this.offContext.font = fontSize + 'vp sans-serif' 3024 this.offContext.fillText(str + '.', 0, fontSize * 0.9) 3025 return this.offContext.getPixelMap(0, 0, fontSize * (str.length + 1) / 1.75, fontSize) 3026 } 3027 3028 public genSquareMark(fontSize: number): PixelMap { 3029 this.offContext = this.offscreenCanvas.getContext("2d", this.settings) 3030 this.clearCanvas() 3031 const coordinate = fontSize * (1 - 1 / 1.5) / 2 3032 const sideLength = fontSize / 1.5 3033 this.offContext.fillRect(coordinate, coordinate, sideLength, sideLength) 3034 return this.offContext.getPixelMap(0, 0, fontSize, fontSize) 3035 } 3036 3037 // Generate a circle symbol. 3038 public genCircleMark(fontSize: number, width: number, level?: number ): PixelMap { 3039 const indentLevel = level ?? 1 3040 const offsetLevel = [22, 28, 32, 34, 38] 3041 const fontSizeLevel = this.getFontSizeLevel(fontSize) 3042 const marginlevel = this.getmarginLevel(width) 3043 const newCanvas = new OffscreenCanvas(canvasWidth, canvasHeight) 3044 const newOffContext: OffscreenCanvasRenderingContext2D = newCanvas.getContext("2d", this.settings) 3045 const centerCoordinate = 50 3046 const radius = 10 3047 this.clearCanvas() 3048 newOffContext.ellipse(100 * (indentLevel + 1) - centerCoordinate * marginlevel, offsetLevel[fontSizeLevel], radius * marginlevel, radius, 0, 0, 2 * Math.PI) 3049 newOffContext.fillStyle = '66FF0000' 3050 newOffContext.fill() 3051 return newOffContext.getPixelMap(0, 0, 100 + 100 * indentLevel, 100) 3052 } 3053 3054 private clearCanvas() { 3055 this.offContext.clearRect(0, 0, canvasWidth, canvasHeight) 3056 } 3057} 3058 3059@Entry 3060@Component 3061struct Index { 3062 controller: RichEditorController = new RichEditorController() 3063 options: RichEditorOptions = { controller: this.controller } 3064 private leadingMarkCreatorInstance = LeadingMarginCreator.instance 3065 private fontNameRawFile: string = 'MiSans-Bold' 3066 @State fs: number = 30 3067 @State cl: number = Color.Black 3068 private leftMargin: Dimension = 0 3069 private richEditorTextStyle: RichEditorTextStyle = {} 3070 3071 aboutToAppear() { 3072 font.registerFont({ 3073 familyName: 'MiSans-Bold', 3074 familySrc: '/font/MiSans-Bold.ttf' 3075 }) 3076 } 3077 3078 build() { 3079 Scroll() { 3080 Column() { 3081 RichEditor(this.options) 3082 .onReady(() => { 3083 this.controller.addTextSpan("0123456789\n", 3084 { 3085 style: 3086 { 3087 fontWeight: 'medium', 3088 fontFamily: this.fontNameRawFile, 3089 fontColor: Color.Red, 3090 fontSize: 50, 3091 fontStyle: FontStyle.Italic, 3092 decoration: { type: TextDecorationType.Underline, color: Color.Green } 3093 } 3094 }) 3095 3096 this.controller.addTextSpan("abcdefg", 3097 { 3098 style: 3099 { 3100 fontWeight: FontWeight.Lighter, 3101 fontFamily: 'HarmonyOS Sans', 3102 fontColor: 'rgba(0,128,0,0.5)', 3103 fontSize: 30, 3104 fontStyle: FontStyle.Normal, 3105 decoration: { type: TextDecorationType.Overline, color: 'rgba(169, 26, 246, 0.50)' } 3106 } 3107 }) 3108 }) 3109 .borderWidth(1) 3110 .borderColor(Color.Green) 3111 .width("100%") 3112 .height("50%") 3113 3114 Row({ space: 5 }) { 3115 Button('setTypingStyle1') 3116 .fontSize(10) 3117 .onClick(() => { 3118 this.controller.setTypingStyle( 3119 { 3120 fontWeight: 'medium', 3121 fontFamily: this.fontNameRawFile, 3122 fontColor: Color.Blue, 3123 fontSize: 50, 3124 fontStyle: FontStyle.Italic, 3125 decoration: { type: TextDecorationType.Underline, color: Color.Green } 3126 }) 3127 }) 3128 3129 Button('setTypingStyle2') 3130 .fontSize(10) 3131 .onClick(() => { 3132 this.controller.setTypingStyle( 3133 { 3134 fontWeight: FontWeight.Lighter, 3135 fontFamily: 'HarmonyOS Sans', 3136 fontColor: Color.Green, 3137 fontSize: '30', 3138 fontStyle: FontStyle.Normal, 3139 decoration: { type: TextDecorationType.Overline, color: 'rgba(169, 26, 246, 0.50)' } 3140 }) 3141 }) 3142 } 3143 Divider() 3144 Button("getTypingStyle").onClick(() => { 3145 this.richEditorTextStyle = this.controller.getTypingStyle() 3146 console.log("RichEditor getTypingStyle:" + JSON.stringify(this.richEditorTextStyle)) 3147 }) 3148 Divider() 3149 Row({ space: 5 }) { 3150 Button ("Increase Bullet Indent").onClick(() => { 3151 let margin = Number(this.leftMargin) 3152 if (margin < 200) { 3153 margin += Indentation 3154 this.leftMargin = margin 3155 } 3156 this.controller.updateParagraphStyle({ 3157 start: -10, 3158 end: -10, 3159 style: { 3160 leadingMargin : { 3161 pixelMap : this.leadingMarkCreatorInstance.genCircleMark(100, margin, 1), 3162 size: [margin, 40] 3163 } 3164 } 3165 }) 3166 }) 3167 3168 Button("Decrease Bullet Indent").onClick(() => { 3169 let margin = Number(this.leftMargin) 3170 if (margin > 0) { 3171 margin -= Indentation 3172 this.leftMargin = margin 3173 } 3174 this.controller.updateParagraphStyle({ 3175 start: -10, 3176 end: -10, 3177 style: { 3178 leadingMargin : { 3179 pixelMap : this.leadingMarkCreatorInstance.genCircleMark(100, margin, 1), 3180 size: [margin, 40] 3181 } 3182 } 3183 }) 3184 }) 3185 } 3186 Divider() 3187 Row({ space: 5 }) { 3188 Button ("Increase Indent").onClick(() => { 3189 let margin = Number(this.leftMargin) 3190 if (margin < 200) { 3191 margin += Indentation 3192 this.leftMargin = margin 3193 } 3194 this.controller.updateParagraphStyle({ 3195 start: -10, 3196 end: -10, 3197 style: { 3198 leadingMargin: margin 3199 } 3200 }) 3201 }) 3202 3203 Button("Decrease Indent").onClick(() => { 3204 let margin = Number(this.leftMargin) 3205 if (margin > 0) { 3206 margin -= Indentation 3207 this.leftMargin = margin 3208 } 3209 this.controller.updateParagraphStyle({ 3210 start: -10, 3211 end: -10, 3212 style: { 3213 leadingMargin: margin 3214 } 3215 }) 3216 }) 3217 } 3218 }.borderWidth(1).borderColor(Color.Red) 3219 } 3220 } 3221} 3222``` 3223 3224 3225### Example 8 3226``` ts 3227@Entry 3228@Component 3229struct Index { 3230 controller: RichEditorController = new RichEditorController(); 3231 options: RichEditorOptions = { controller: this.controller }; 3232 private start: number = -1; 3233 private end: number = -1; 3234 @State message: string = "[-1, -1]" 3235 @State content: string = "" 3236 @State visable :number = 0; 3237 @State index:number = 0; 3238 @State offsetx: number = 0; 3239 @State textShadows : (ShadowOptions | Array<ShadowOptions> ) = 3240 [{ radius: 10, color: Color.Red, offsetX: 10, offsetY: 0 },{ radius: 10, color: Color.Black, offsetX: 20, offsetY: 0 }, 3241 { radius: 10, color: Color.Brown, offsetX: 30, offsetY: 0 },{ radius: 10, color: Color.Green, offsetX: 40, offsetY: 0 }, 3242 { radius: 10, color: Color.Yellow, offsetX: 100, offsetY: 0 }] 3243 @State textshadowOf : ShadowOptions[] = [] 3244 build() { 3245 Column() { 3246 Column() { 3247 Text("selection range:").width("100%") 3248 Text() { 3249 Span(this.message) 3250 }.width("100%") 3251 Text("selection content:").width("100%") 3252 Text() { 3253 Span(this.content) 3254 }.width("100%") 3255 } 3256 .borderWidth(1) 3257 .borderColor(Color.Red) 3258 .width("100%") 3259 .height("20%") 3260 Row() { 3261 Button("Update Style: Bold & Text Shadow").onClick(() => { 3262 this.controller.updateSpanStyle({ 3263 start: this.start, 3264 end: this.end, 3265 textStyle: 3266 { 3267 fontWeight: FontWeight.Bolder, 3268 textShadow: this.textShadows 3269 } 3270 }) 3271 }) 3272 } 3273 .borderWidth(1) 3274 .borderColor(Color.Red) 3275 .width("100%") 3276 .height("10%") 3277 Column() { 3278 RichEditor(this.options) 3279 .onReady(() => { 3280 this.controller.addTextSpan("0123456789", 3281 { 3282 style: 3283 { 3284 fontColor: Color.Orange, 3285 fontSize: 30, 3286 textShadow: { radius: 10, color: Color.Blue, offsetX: 10, offsetY: 0 } 3287 } 3288 }) 3289 }) 3290 .borderWidth(1) 3291 .borderColor(Color.Green) 3292 .width("100%") 3293 .height("30%") 3294 } 3295 .borderWidth(1) 3296 .borderColor(Color.Red) 3297 .width("100%") 3298 .height("70%") 3299 } 3300 } 3301} 3302``` 3303 3304 3305 3306### Example 9 3307``` ts 3308@Builder 3309function placeholderBuilder2() { 3310 Row({ space: 2 }) { 3311 Image($r("app.media.icon")).width(24).height(24).margin({ left: -5 }) 3312 Text('okokokok').fontSize(10) 3313 }.width('20%').height(50).padding(10).backgroundColor(Color.Red) 3314} 3315 3316// xxx.ets 3317@Entry 3318@Component 3319struct Index { 3320 controller: RichEditorController = new RichEditorController(); 3321 option: RichEditorOptions = { controller: this.controller }; 3322 private start: number = 2; 3323 private end: number = 4; 3324 @State message: string = "[-1, -1]" 3325 @State content: string = "" 3326 private my_offset: number | undefined = undefined 3327 private my_builder: CustomBuilder = undefined 3328 3329 @Builder 3330 placeholderBuilder() { 3331 Row({ space: 2 }) { 3332 Image($r("app.media.icon")).width(24).height(24).margin({ left: -5 }) 3333 Text('Custom Popup').fontSize(10) 3334 }.width(100).height(50).padding(5) 3335 } 3336 3337 @Builder 3338 placeholderBuilder3() { 3339 Text("hello").padding('20').borderWidth(1).width('100%') 3340 } 3341 3342 @Builder 3343 placeholderBuilder4() { 3344 Column() { 3345 Column({ space: 5 }) { 3346 Text('direction:Row').fontSize(9).fontColor(0xCCCCCC).width('90%') 3347 Flex({ direction: FlexDirection.Row }) { // The child components are arranged in the same direction as the main axis runs along the rows. 3348 Text('1').width('20%').height(50).backgroundColor(0xF5DEB3) 3349 Text('1').width('20%').height(50).backgroundColor(0xD2B48C) 3350 Text('1').width('20%').height(50).backgroundColor(0xF5DEB3) 3351 Text('1').width('20%').height(50).backgroundColor(0xD2B48C) 3352 } 3353 .height(70) 3354 .width('90%') 3355 .padding(10) 3356 .backgroundColor(0xAFEEEE) 3357 3358 Text('direction:RowReverse').fontSize(9).fontColor(0xCCCCCC).width('90%') 3359 Flex({ direction: FlexDirection.RowReverse }) { // The child components are arranged opposite to the Row direction. 3360 Text('1').width('20%').height(50).backgroundColor(0xF5DEB3) 3361 Text('1').width('20%').height(50).backgroundColor(0xD2B48C) 3362 Text('1').width('20%').height(50).backgroundColor(0xF5DEB3) 3363 Text('1').width('20%').height(50).backgroundColor(0xD2B48C) 3364 } 3365 .height(70) 3366 .width('90%') 3367 .padding(10) 3368 .backgroundColor(0xAFEEEE) 3369 3370 Text('direction:Column').fontSize(9).fontColor(0xCCCCCC).width('90%') 3371 Flex({ direction: FlexDirection.Column }) { // The child components are arranged in the same direction as the main axis runs down the columns. 3372 Text('1').width('20%').height(40).backgroundColor(0xF5DEB3) 3373 Text('1').width('20%').height(40).backgroundColor(0xD2B48C) 3374 Text('1').width('20%').height(40).backgroundColor(0xF5DEB3) 3375 Text('1').width('20%').height(40).backgroundColor(0xD2B48C) 3376 } 3377 .height(160) 3378 .width('90%') 3379 .padding(10) 3380 .backgroundColor(0xAFEEEE) 3381 3382 Text('direction:ColumnReverse').fontSize(9).fontColor(0xCCCCCC).width('90%') 3383 Flex({ direction: FlexDirection.ColumnReverse }) { // The child components are arranged opposite to the Column direction. 3384 Text('1').width('20%').height(40).backgroundColor(0xF5DEB3) 3385 Text('1').width('20%').height(40).backgroundColor(0xD2B48C) 3386 Text('1').width('20%').height(40).backgroundColor(0xF5DEB3) 3387 Text('1').width('20%').height(40).backgroundColor(0xD2B48C) 3388 } 3389 .height(160) 3390 .width('90%') 3391 .padding(10) 3392 .backgroundColor(0xAFEEEE) 3393 }.width('100%').margin({ top: 5 }) 3394 }.width('100%') 3395 } 3396 3397 @Builder 3398 MyMenu() { 3399 Menu() { 3400 MenuItem({ startIcon: $r("app.media.icon"), content: "Menu option 1" }) 3401 MenuItem({ startIcon: $r("app.media.icon"), content: "Menu option 2" }) 3402 .enabled(false) 3403 } 3404 } 3405 3406 build() { 3407 Column() { 3408 Column() { 3409 Text("selection range:").width("100%") 3410 Text() { 3411 Span(this.message) 3412 }.width("100%") 3413 3414 Text("selection content:").width("100%") 3415 Text() { 3416 Span(this.content) 3417 }.width("100%") 3418 } 3419 .borderWidth(1) 3420 .borderColor(Color.Red) 3421 .width("100%") 3422 .height("20%") 3423 3424 Row() { 3425 Button ("Get Span Info").onClick () => { 3426 console.info('getSpans='+JSON.stringify(this.controller.getSpans({ start:1, end:5 }))) 3427 console.info('getParagraphs='+JSON.stringify(this.controller.getParagraphs({ start:1, end:5 }))) 3428 this.content = "" 3429 this.controller.getSpans({ 3430 start: this.start, 3431 end: this.end 3432 }).forEach(item => { 3433 if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') { 3434 if ((item as RichEditorImageSpanResult).valueResourceStr == "") { 3435 console.info("builder span index " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range : " + (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + 3436 (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + (item as RichEditorImageSpanResult).imageStyle[0] + ", " + (item as RichEditorImageSpanResult).imageStyle[1]) 3437 } else { 3438 console.info("image span " + (item as RichEditorImageSpanResult).valueResourceStr + ", index : " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range: " + 3439 (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + 3440 (item as RichEditorImageSpanResult).imageStyle.size[0] + ", " + (item as RichEditorImageSpanResult).imageStyle.size[1]) 3441 } 3442 } else { 3443 this.content += (item as RichEditorTextSpanResult).value; 3444 this.content += "\n" 3445 console.info("text span: " + (item as RichEditorTextSpanResult).value) 3446 } 3447 }) 3448 }) 3449 Button ("Get Selection").onClick () => { 3450 this.content = ""; 3451 let select = this.controller.getSelection() 3452 console.info("selection start " + select.selection[0] + " end " + select.selection[1]) 3453 select.spans.forEach(item => { 3454 if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') { 3455 if ((item as RichEditorImageSpanResult).valueResourceStr == "") { 3456 console.info("builder span index " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range : " + (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + 3457 (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + (item as RichEditorImageSpanResult).imageStyle[0] + ", " + (item as RichEditorImageSpanResult).imageStyle[1]) 3458 } else { 3459 console.info("image span " + (item as RichEditorImageSpanResult).valueResourceStr + ", index : " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range: " + 3460 (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + 3461 (item as RichEditorImageSpanResult).imageStyle.size[0] + ", " + (item as RichEditorImageSpanResult).imageStyle.size[1]) 3462 } 3463 } else { 3464 this.content += (item as RichEditorTextSpanResult).value; 3465 this.content += "\n" 3466 console.info("text span: " + (item as RichEditorTextSpanResult).value) 3467 } 3468 }) 3469 }) 3470 Button("Delete Selection").onClick(() => { 3471 this.controller.deleteSpans({ 3472 start: this.start, 3473 end: this.end 3474 }) 3475 }) 3476 } 3477 .borderWidth(1) 3478 .borderColor(Color.Red) 3479 .width("100%") 3480 .height("10%") 3481 3482 Column() { 3483 RichEditor(this.option) 3484 .onReady(() => { 3485 this.controller.addTextSpan("0123456789", 3486 { 3487 style: 3488 { 3489 fontColor: Color.Orange, 3490 fontSize: 30 3491 } 3492 }) 3493 this.controller.addImageSpan($r("app.media.icon"), 3494 { 3495 imageStyle: 3496 { 3497 size: ["57px", "57px"] 3498 } 3499 }) 3500 }) 3501 .onSelect((value: RichEditorSelection) => { 3502 this.start = value.selection[0]; 3503 this.end = value.selection[1]; 3504 this.message = "[" + this.start + ", " + this.end + "]" 3505 console.info("onSelect="+JSON.stringify(value)) 3506 }) 3507 .aboutToIMEInput((value: RichEditorInsertValue) => { 3508 console.log("---------------------- aboutToIMEInput --------------------") 3509 console.info("aboutToIMEInput="+JSON.stringify(value)) 3510 console.log("insertOffset:" + value.insertOffset) 3511 console.log("insertValue:" + value.insertValue) 3512 return true; 3513 }) 3514 .onIMEInputComplete((value: RichEditorTextSpanResult) => { 3515 console.log("---------------------- onIMEInputComplete --------------------") 3516 console.info("onIMEInputComplete="+JSON.stringify(value)) 3517 console.log("spanIndex:" + value.spanPosition.spanIndex) 3518 console.log("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]") 3519 console.log("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]") 3520 console.log("value:" + value.value) 3521 }) 3522 .aboutToDelete((value: RichEditorDeleteValue) => { 3523 value.richEditorDeleteSpans.forEach(item => { 3524 console.log("---------------------- item --------------------") 3525 console.info("spanIndex=" + item.spanPosition.spanIndex) 3526 console.log("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]") 3527 console.log("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]") 3528 if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') { 3529 if ((item as RichEditorImageSpanResult).valueResourceStr == "") { 3530 console.info("builder span index " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range : " + (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + 3531 (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + (item as RichEditorImageSpanResult).imageStyle[0] + ", " + (item as RichEditorImageSpanResult).imageStyle[1]) 3532 } else { 3533 console.info("image span " + (item as RichEditorImageSpanResult).valueResourceStr + ", index : " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range: " + 3534 (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + 3535 (item as RichEditorImageSpanResult).imageStyle.size[0] + ", " + (item as RichEditorImageSpanResult).imageStyle.size[1]) 3536 } 3537 } else { 3538 console.info("delete text: " + (item as RichEditorTextSpanResult).value) 3539 } 3540 }) 3541 return true; 3542 }) 3543 .borderWidth(1) 3544 .borderColor(Color.Green) 3545 .width("100%") 3546 .height("30%") 3547 3548 Button("add span") 3549 .onClick(() => { 3550 let num = this.controller.addBuilderSpan(this.my_builder, { offset: this.my_offset }) 3551 console.info('addBuilderSpan return ' + num) 3552 }) 3553 Button("add image") 3554 .onClick(() => { 3555 let num = this.controller.addImageSpan($r("app.media.icon"), { 3556 imageStyle: { 3557 size: ["50px", "50px"], 3558 verticalAlign: ImageSpanAlignment.BOTTOM, 3559 layoutStyle: { 3560 borderRadius: undefined, 3561 margin: undefined 3562 } 3563 } 3564 }) 3565 console.info('addImageSpan return' + num) 3566 }) 3567 Row() { 3568 Button('builder1').onClick(() => { 3569 this.my_builder = () => { 3570 this.placeholderBuilder() 3571 } 3572 }) 3573 Button('builder2').onClick(() => { 3574 this.my_builder = placeholderBuilder2.bind(this) 3575 }) 3576 Button('builder3').onClick(() => { 3577 this.my_builder = () => { 3578 this.placeholderBuilder3() 3579 } 3580 }) 3581 Button('builder4').onClick(() => { 3582 this.my_builder = () => { 3583 this.placeholderBuilder4() 3584 } 3585 }) 3586 } 3587 } 3588 .borderWidth(1) 3589 .borderColor(Color.Red) 3590 .width("100%") 3591 .height("70%") 3592 } 3593 } 3594} 3595``` 3596 3597 3598### Example 10 3599Example of using **enableDataDetector** and **dataDetectorConfig** 3600 3601```ts 3602@Entry 3603@Component 3604struct TextExample7 { 3605 controller: RichEditorController = new RichEditorController(); 3606 options: RichEditorOptions = { controller: this.controller }; 3607 @State phoneNumber: string = '(86) (755) ********'; 3608 @State url: string = 'www.********.com'; 3609 @State email: string = '***@example.com'; 3610 @State address: string = 'Street A, city B, state C'; 3611 @State enableDataDetector: boolean = true; 3612 @State enablePreviewText: boolean = false; 3613 @State types: TextDataDetectorType[] = []; 3614 3615 build() { 3616 Row() { 3617 Column() { 3618 RichEditor(this.options) 3619 .onReady(() => { 3620 this.controller.addTextSpan('Phone number:' + this.phoneNumber + '\n', 3621 { 3622 style: 3623 { 3624 fontSize: 30 3625 } 3626 }) 3627 this.controller.addTextSpan('URL:' + this.url + '\n', 3628 { 3629 style: 3630 { 3631 fontSize: 30 3632 } 3633 }) 3634 this.controller.addTextSpan('Email:' + this.email + '\n', 3635 { 3636 style: 3637 { 3638 fontSize: 30 3639 } 3640 }) 3641 this.controller.addTextSpan('Address:' + this.address, 3642 { 3643 style: 3644 { 3645 fontSize: 30 3646 } 3647 }) 3648 }) 3649 .copyOptions(CopyOptions.InApp) 3650 .enableDataDetector(this.enableDataDetector) 3651 .dataDetectorConfig({types : this.types, onDetectResultUpdate: (result: string)=>{}}) 3652 .enablePreviewText(this.enablePreviewText) 3653 .borderWidth(1) 3654 .padding(10) 3655 .width('100%') 3656 } 3657 .width('100%') 3658 } 3659 } 3660} 3661``` 3662### Example 11 3663This example shows how to use **caretColor** and **selectedBackgroundColor**. 3664``` ts 3665@Entry 3666@Component 3667struct RichEditorDemo { 3668 @State color: Color|string = "" 3669 controller: RichEditorController = new RichEditorController(); 3670 build() { 3671 Column() { 3672 Row(){ 3673 Button("Change to Red").onClick(() => { 3674 this.color = Color.Red 3675 }) 3676 }.margin({top:50}) 3677 RichEditor({ controller: this.controller }) 3678 .onReady(()=>{ 3679 this.controller.addTextSpan('This is for testing') 3680 }) 3681 .width("100%") 3682 .border({ width: 1, radius: 5 }) 3683 .key('RichEditor') 3684 .caretColor(this.color) // Caret color 3685 .selectedBackgroundColor(this.color) // Background color of the selected content. 3686 .margin({top:50}) 3687 } 3688 .width('100%') 3689 } 3690} 3691``` 3692 3693 3694### Example 12 3695This example shows the usage of **lineHeight** and **letterSpacing**. 3696```ts 3697@Entry 3698@Component 3699struct RichEditorDemo03 { 3700 controller: RichEditorController = new RichEditorController(); 3701 options: RichEditorOptions = { controller: this.controller }; 3702 @State start: number = -1; 3703 @State end: number = -1; 3704 @State LH:number = 50 3705 @State LS:number = 20 3706 3707 build() { 3708 Column() { 3709 Scroll(){ 3710 Column(){ 3711 Row() { 3712 Button("Line Height ++").onClick(()=>{ 3713 this.LH = this.LH + 5 3714 this.controller.updateSpanStyle({ 3715 start: this.start, 3716 end: this.end, 3717 textStyle: 3718 { 3719 lineHeight: this.LH 3720 } 3721 }) 3722 }) 3723 Button("Line Height --").onClick(()=>{ 3724 this.LH = this.LH - 5 3725 this.controller.updateSpanStyle({ 3726 start: this.start, 3727 end: this.end, 3728 textStyle: 3729 { 3730 lineHeight: this.LH 3731 } 3732 }) 3733 }) 3734 Button("Letter Spacing ++").onClick (()=>{ 3735 this.LS = this.LS + 5 3736 this.controller.updateSpanStyle({ 3737 start: this.start, 3738 end: this.end, 3739 textStyle: 3740 { 3741 letterSpacing: this.LS 3742 } 3743 }) 3744 }) 3745 Button("Letter Spacing --").onClick (()=>{ 3746 this.LS = this.LS - 5 3747 this.controller.updateSpanStyle({ 3748 start: this.start, 3749 end: this.end, 3750 textStyle: 3751 { 3752 letterSpacing: this.LS 3753 } 3754 }) 3755 }) 3756 } 3757 } 3758 }.borderWidth(1) 3759 .borderColor(Color.Red) 3760 .width("100%") 3761 .height("20%") 3762 .margin({top: 20}) 3763 3764 Scroll(){ 3765 Column() { 3766 Text("LineHeight:" + this.LH).width("100%") 3767 Text("LetterSpacing:" + this.LS).width("100%") 3768 } 3769 } 3770 .borderWidth(1) 3771 .borderColor(Color.Red) 3772 .width("100%") 3773 .height("20%") 3774 .margin({bottom: 20}) 3775 3776 Column() { 3777 RichEditor(this.options).clip(true).padding(10) 3778 .onReady(() => { 3779 this.controller.addTextSpan("012345", 3780 { 3781 style: 3782 { 3783 fontColor: Color.Orange, 3784 fontSize: 30, 3785 lineHeight: this.LH, 3786 letterSpacing: this.LS 3787 } 3788 }) 3789 this.controller.addTextSpan("6789", 3790 { 3791 style: 3792 { 3793 fontColor: Color.Black, 3794 fontSize: 30, 3795 lineHeight: this.LH, 3796 letterSpacing: this.LS 3797 } 3798 }) 3799 }) 3800 .borderWidth(1) 3801 .borderColor(Color.Green) 3802 .width(400) 3803 .height(400) 3804 } 3805 .borderWidth(1) 3806 .borderColor(Color.Red) 3807 .width("100%") 3808 .height("60%") 3809 } 3810 } 3811} 3812``` 3813 3814 3815### Example 13 3816This example shows the usage of **preventDefault**. 3817```ts 3818@Entry 3819@Component 3820struct RichEditorDemo { 3821 controller: RichEditorController = new RichEditorController(); 3822 options: RichEditorOptions = { controller: this.controller }; 3823 3824 build() { 3825 Column({ space: 2 }) { 3826 RichEditor(this.options) 3827 .onReady(() => { 3828 this.controller.addTextSpan('RichEditor preventDefault') 3829 }) 3830 .onPaste((event?: PasteEvent) => { 3831 if (event != undefined && event.preventDefault) { 3832 event.preventDefault(); 3833 } 3834 }) 3835 .borderWidth(1) 3836 .borderColor(Color.Green) 3837 .width('100%') 3838 .height('40%') 3839 } 3840 } 3841} 3842``` 3843 3844 3845### Example 14 3846 3847This example sets the **FontFeature** attribute to **ss01**, which changes the digit "0" from its original oval shape to a shape with rounded corners. 3848 3849```ts 3850@Entry 3851@Component 3852struct RichEditorExample { 3853 controller: RichEditorController = new RichEditorController(); 3854 options: RichEditorOptions = { controller: this.controller }; 3855 @State enableDataDetector: boolean = true; 3856 @State types: TextDataDetectorType[] = []; 3857 build() { 3858 Row() { 3859 Column() { 3860 RichEditor(this.options) 3861 .onReady(() => { 3862 this.controller.addTextSpan('This is ss01 off :' + '0000' + '\n', 3863 { 3864 style: 3865 { 3866 fontSize: 30 3867 } 3868 }) 3869 this.controller.addTextSpan('This is ss01 on :' + '0000' + '\n', 3870 { 3871 style: 3872 { 3873 fontSize: 30, 3874 fontFeature: "\"ss01\" 1" 3875 } 3876 }) 3877 }) 3878 .copyOptions(CopyOptions.InApp) 3879 .enableDataDetector(this.enableDataDetector) 3880 .dataDetectorConfig({types : this.types, onDetectResultUpdate: (result: string)=>{}}) 3881 .borderWidth(1) 3882 .padding(10) 3883 .width('100%') 3884 } 3885 .width('100%') 3886 .margin({top:150}) 3887 } 3888 } 3889} 3890``` 3891 3892 3893### Example 15 3894 3895This example shows how to support custom keyboard avoidance. 3896 3897```ts 3898@Entry 3899@Component 3900struct RichEditorExample { 3901 controller: RichEditorController = new RichEditorController() 3902 @State height1:string|number = '80%' 3903 @State height2:number = 100 3904 @State supportAvoidance:boolean = true; 3905 3906 // Create a custom keyboard component. 3907 @Builder CustomKeyboardBuilder() { 3908 Column() { 3909 Row(){ 3910 Button('Add Emoticon').onClick(() => { 3911 this.controller.addTextSpan("\uD83D\uDE0A", 3912 { 3913 style: 3914 { 3915 fontColor: Color.Orange, 3916 } 3917 }) 3918 }) 3919 } 3920 Grid() { 3921 ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, '*', 0, '#'], (item: number | string) => { 3922 GridItem() { 3923 Button(item + "") 3924 .width(110).onClick(() => { 3925 this.controller.addTextSpan(item + '', { 3926 offset: this.controller.getCaretOffset(), 3927 style: 3928 { 3929 fontColor: Color.Orange, 3930 fontSize: 30 3931 } 3932 }) 3933 this.controller.setCaretOffset(this.controller.getCaretOffset() + item.toString().length) 3934 }) 3935 } 3936 }) 3937 }.maxCount(3).columnsGap(10).rowsGap(10).padding(5) 3938 }.backgroundColor(Color.Gray) 3939 } 3940 3941 build() { 3942 Column() { 3943 Row(){ 3944 Button("20%") 3945 .fontSize(24) 3946 .onClick(()=>{ 3947 this.height1 = "20%" 3948 }) 3949 Button("80%") 3950 .fontSize(24) 3951 .margin({left:20}) 3952 .onClick(()=>{ 3953 this.height1 = "80%" 3954 }) 3955 } 3956 .justifyContent(FlexAlign.Center) 3957 .alignItems(VerticalAlign.Bottom) 3958 .height(this.height1) 3959 .width("100%") 3960 .padding({bottom:50}) 3961 RichEditor({ controller: this.controller }) 3962 // Bind the custom keyboard. 3963 .customKeyboard(this.CustomKeyboardBuilder(),{ supportAvoidance: this.supportAvoidance }).margin(10).border({ width: 1 }) 3964 .borderWidth(1) 3965 .borderColor(Color.Red) 3966 .width("100%") 3967 } 3968 } 3969} 3970``` 3971 3972 3973### Example 16 3974 3975This example shows the usage of **onEditingChange** and **isEditing**. 3976 3977```ts 3978@Entry 3979@Component 3980struct RichEditor_onEditingChange { 3981 controller: RichEditorController = new RichEditorController() 3982 @State controllerIsEditing: boolean = false 3983 @Builder 3984 3985 build() { 3986 Column() { 3987 Row() { 3988 Button("View Editing State: isEditing():").onClick(() => { 3989 this.controllerIsEditing = this.controller.isEditing() 3990 }) 3991 .padding(5) 3992 Text('' + this.controllerIsEditing) 3993 .width('100%') 3994 .padding(5) 3995 .fontColor(Color.Orange) 3996 .fontSize(20) 3997 } 3998 RichEditor({ controller: this.controller }) 3999 .onEditingChange((isEditing: boolean) => { 4000 console.log("Current Editing Status:" + isEditing) 4001 }) 4002 .height(400) 4003 .borderWidth(1) 4004 .borderColor(Color.Red) 4005 .width("100%") 4006 } 4007 } 4008} 4009``` 4010 4011 4012 4013### Example 17 4014 4015This example shows the usage of **onWillChange**, **onDidChange**, **onCut**, and **onCopy**. 4016 4017```ts 4018@Entry 4019@Component 4020struct RichEditorExample { 4021 controller: RichEditorController = new RichEditorController() 4022 build() { 4023 Column() { 4024 RichEditor({ controller: this.controller }) 4025 .height(200) 4026 .borderWidth(1) 4027 .borderColor(Color.Red) 4028 .width("100%") 4029 .onReady(() => { 4030 this.controller.addTextSpan('TestWord', { style: { fontColor: Color.Orange, fontSize: 30 } }) 4031 this.controller.updateSpanStyle({ 4032 start: -1, 4033 end: -1, 4034 textStyle: 4035 { 4036 fontWeight: FontWeight.Bolder 4037 } 4038 }) 4039 }) 4040 .onWillChange((value: RichEditorChangeValue) => { 4041 console.log('Test log: onWillChange') 4042 console.log('rangeBefore: ' + JSON.stringify(value.rangeBefore)) 4043 console.log('print replacedSpans') 4044 value.replacedSpans.forEach((item: RichEditorTextSpanResult) => { 4045 console.log('spanPosition:' + JSON.stringify(item.spanPosition)) 4046 console.log('value:' + item.value) 4047 console.log('textStyle:' + JSON.stringify(item.textStyle)) 4048 console.log('offsetInSpan:' + item.offsetInSpan) 4049 console.log('valueResource:' + item.valueResource) 4050 console.log('paragraphStyle:' + JSON.stringify(item.paragraphStyle)) 4051 }) 4052 console.log('print replacedImageSpans') 4053 value.replacedImageSpans.forEach((item: RichEditorImageSpanResult) => { 4054 console.log('spanPosition:' + JSON.stringify(item.spanPosition)) 4055 console.log('valuePixelMap:' + JSON.stringify(item.valuePixelMap)) 4056 console.log('valueResourceStr:' + item.valueResourceStr) 4057 console.log('imageStyle:' + JSON.stringify(item.imageStyle)) 4058 console.log('offsetInSpan:' + item.offsetInSpan) 4059 }) 4060 console.log('print replacedSymbolSpans') 4061 value.replacedSymbolSpans.forEach((item: RichEditorTextSpanResult) => { 4062 console.log('spanPosition:' + JSON.stringify(item.spanPosition)) 4063 console.log('value:' + item.value) 4064 console.log('offsetInSpan:' + item.offsetInSpan) 4065 console.log('symbolSpanStyle:' + JSON.stringify(item.symbolSpanStyle)) 4066 console.log('valueResource:' + item.valueResource) 4067 console.log('paragraphStyle:' + JSON.stringify(item.paragraphStyle)) 4068 }) 4069 return true 4070 }) 4071 .onDidChange((rangeBefore: TextRange, rangeAfter: TextRange) => { 4072 console.log('Test log: onDidChange') 4073 console.log('rangeBefore:' + JSON.stringify(rangeBefore)) 4074 console.log('rangeAfter:' + JSON.stringify(rangeAfter)) 4075 }) 4076 .onCut((event:CutEvent) => { 4077 event.preventDefault!() 4078 console.log('Test log: onCut') 4079 }) 4080 .onCopy((event:CopyEvent) => { 4081 event.preventDefault!() 4082 console.log('Test log: onCopy') 4083 }) 4084 .onPaste(()=>{ 4085 console.log('Test log: onPaste') 4086 }) 4087 Text ('Test text Hello') 4088 .lineHeight(50) 4089 .fontSize(24) 4090 .draggable(true) 4091 .onDragStart(()=>{}) 4092 TextInput({text:'Test text NiHao'}) 4093 .draggable(true) 4094 .margin(20) 4095 } 4096 } 4097} 4098``` 4099### Example 18 4100 4101This example shows the usage of **enterKeyType**, **onSubmit**, and **stopEditing**. 4102 4103```ts 4104@Entry 4105@Component 4106struct SoftKeyboardEnterTypeExample { 4107 controller: RichEditorController = new RichEditorController() 4108 4109 build() { 4110 Column() { 4111 Button("Stop Editing").onClick(()=>{ 4112 this.controller.stopEditing() 4113 }) 4114 RichEditor({ controller: this.controller }) 4115 .margin(10) 4116 .border({ width: 1 }) 4117 .height(200) 4118 .borderWidth(1) 4119 .borderColor(Color.Red) 4120 .width("100%") 4121 .enterKeyType(EnterKeyType.Search) 4122 .onSubmit((enterKey: EnterKeyType, event: SubmitEvent) => { 4123 console.log("trigger richeditor onsubmit" + enterKey); 4124 this.controller.addTextSpan(" type["+ enterKey +"] triggerred") 4125 event.keepEditableState(); 4126 }) 4127 }.height("100%").justifyContent(FlexAlign.Center) 4128 } 4129} 4130``` 4131 4132 4133 4134### Example 19 4135This example demonstrates how to set, update, and query the value of **lineBreakStrategy**. 4136 4137```ts 4138@Entry 4139@Component 4140struct LineBreakStrategyExample { 4141 controller: RichEditorController = new RichEditorController(); 4142 private spanParagraphs: RichEditorParagraphResult[] = []; 4143 @State lineBreakOptionStr: string[] = ['GREEDY', 'HIGH_QUALITY', 'BALANCED'] 4144 @State attributeValue: string = "" 4145 @State testStr: string = "0123456789,0123456789,0123456789,0123456789,0123456789." 4146 build() { 4147 Column() { 4148 RichEditor({ controller: this.controller }) 4149 .onReady(() => { 4150 this.controller.addTextSpan(this.testStr, { 4151 style: { 4152 fontColor: Color.Black, 4153 fontSize: "32", 4154 }, 4155 paragraphStyle: { 4156 textAlign: TextAlign.Start, 4157 lineBreakStrategy: LineBreakStrategy.GREEDY 4158 } 4159 }) 4160 }) 4161 .width(400) 4162 .height(300) 4163 .margin({bottom:20}) 4164 .draggable(false) 4165 Column(){ 4166 Text('linebreak value: ' + this.attributeValue).fontSize(20).fontColor(Color.Black) 4167 }.margin({bottom: 10}) 4168 Column({ space: 10 }) { 4169 Button("Set LineBreakStrategy to GREEDY").onClick(() => { 4170 this.controller.updateParagraphStyle({ start: -1, end: -1, 4171 style: { 4172 lineBreakStrategy: LineBreakStrategy.GREEDY, 4173 } 4174 }) 4175 }) 4176 Button("Set LineBreakStrategy to HIGH_QUALITY").onClick(() => { 4177 this.controller.updateParagraphStyle({ start: -1, end: -1, 4178 style: { 4179 lineBreakStrategy: LineBreakStrategy.HIGH_QUALITY, 4180 } 4181 }) 4182 }) 4183 Button("Set LineBreakStrategy to BALANCED").onClick(() => { 4184 this.controller.updateParagraphStyle({ start: -1, end: -1, 4185 style: { 4186 lineBreakStrategy: LineBreakStrategy.BALANCED, 4187 } 4188 }) 4189 }) 4190 Divider() 4191 Row(){ 4192 Button("Get LineBreakStrategy Value").onClick(() => { 4193 this.spanParagraphs = this.controller.getParagraphs({ start: -1, end: -1 }) 4194 console.log("RichEditor getParagraphs:" + JSON.stringify(this.spanParagraphs)) 4195 this.spanParagraphs.forEach(item => { 4196 if(typeof(item as RichEditorParagraphResult)['style'] != 'undefined'){ 4197 this.attributeValue = "" 4198 console.info('lineBreakStrategy:'+ JSON.stringify((item as RichEditorParagraphResult)['style'])) 4199 this.attributeValue += this.lineBreakOptionStr[Number((item as RichEditorParagraphResult)['style'].lineBreakStrategy)]; 4200 } 4201 }) 4202 }) 4203 } 4204 } 4205 } 4206 } 4207} 4208``` 4209 4210 4211 4212### Example: 20 4213This example shows the usage of a styled string. 4214 4215```ts 4216import { LengthMetrics } from '@kit.ArkUI' 4217import { image } from '@kit.ImageKit' 4218 4219@Entry 4220@Component 4221struct Index { 4222 stringLength: number = 0; 4223 imagePixelMap: image.PixelMap | undefined = undefined; 4224 @State selection: string = ""; 4225 @State content: string = ""; 4226 @State range: string = ""; 4227 @State replaceString: string = ""; 4228 @State rangeBefore: string = ""; 4229 @State rangeAfter: string = ""; 4230 richEditorStyledString: MutableStyledString = new MutableStyledString(""); 4231 textStyle: TextStyle = new TextStyle({ 4232 fontWeight: FontWeight.Lighter, 4233 fontFamily: 'HarmonyOS Sans', 4234 fontColor: Color.Green, 4235 fontSize: LengthMetrics.vp(30), 4236 fontStyle: FontStyle.Normal 4237 }) 4238 fontStyle1: TextStyle = new TextStyle({ fontColor: Color.Blue }); 4239 fontStyle2: TextStyle = new TextStyle({ 4240 fontWeight: FontWeight.Bolder, 4241 fontFamily: 'Arial', 4242 fontColor: Color.Orange, 4243 fontSize: LengthMetrics.vp(30), 4244 fontStyle: FontStyle.Italic 4245 }) 4246 // Create a styled string object. 4247 mutableStyledString: MutableStyledString = new MutableStyledString("Initial styled string", 4248 [{ start: 0, length: 5, styledKey: StyledStringKey.FONT, styledValue: this.fontStyle1 }]); 4249 styledString: StyledString = new StyledString("Styled string to insert", 4250 [{ start: 2, length: 4, styledKey: StyledStringKey.FONT, styledValue: this.fontStyle2 }]); 4251 controller: RichEditorStyledStringController = new RichEditorStyledStringController(); 4252 options: RichEditorStyledStringOptions = {controller: this.controller}; 4253 // Text content change callback 4254 contentChangedListener: StyledStringChangedListener = { 4255 onWillChange: (value: StyledStringChangeValue) => { 4256 this.range = '[ ' + value.range.start + ' , ' + value.range.end + ' ]'; 4257 this.replaceString = value.replacementString.getString(); 4258 return true; 4259 }, 4260 onDidChange: (rangeBefore, rangeAfter) => { 4261 this.rangeBefore = '[ ' + rangeBefore.start + ' , ' + rangeBefore.end + ' ]'; 4262 this.rangeAfter = '[ ' + rangeAfter.start + ' , ' + rangeAfter.end + ' ]'; 4263 } 4264 } 4265 4266 async aboutToAppear() { 4267 console.info("aboutToAppear initial imagePixelMap"); 4268 this.imagePixelMap = await this.getPixmapFromMedia($r('app.media.icon')); 4269 } 4270 4271 private async getPixmapFromMedia(resource: Resource) { 4272 let unit8Array = await getContext(this)?.resourceManager?.getMediaContent({ 4273 bundleName: resource.bundleName, 4274 moduleName: resource.moduleName, 4275 id: resource.id 4276 }) 4277 let imageSource = image.createImageSource(unit8Array.buffer.slice(0, unit8Array.buffer.byteLength)) 4278 let createPixelMap: image.PixelMap = await imageSource.createPixelMap({ 4279 desiredPixelFormat: image.PixelMapFormat.RGBA_8888 4280 }) 4281 await imageSource.release() 4282 return createPixelMap 4283 } 4284 4285 4286 build() { 4287 Column() { 4288 Column() { 4289 Text("Selection information") 4290 .fontSize(20) 4291 .width("100%") 4292 Text("selection range: " + this.selection).width("100%") 4293 Text("selection content: " + this.content).width("100%") 4294 } 4295 .borderWidth(1) 4296 .borderColor(Color.Black) 4297 .width("100%") 4298 .height("10%") 4299 4300 Column() { 4301 Text("onWillChange callback") 4302 .fontSize(20) 4303 .width("100%") 4304 Text("range: " + this.range).width("100%") 4305 Text("replacementString: " + this.replaceString).width("100%") 4306 Tex ("onWillChange callback") 4307 .fontSize(20) 4308 .width("100%") 4309 Text("rangeBefore: " + this.rangeBefore).width("100%") 4310 Text("rangeAfter: " + this.rangeAfter).width("100%") 4311 } 4312 .borderWidth(1) 4313 .borderColor(Color.Black) 4314 .width("100%") 4315 .height("20%") 4316 4317 RichEditor(this.options) 4318 .onReady(() => { 4319 // Register a text change callback. 4320 this.controller.onContentChanged(this.contentChangedListener); 4321 // Set the styled string displayed in the component. 4322 this.controller.setStyledString(this.mutableStyledString); 4323 }) 4324 .height("20%") 4325 .width("100%") 4326 .borderWidth(1) 4327 .borderColor(Color.Black) 4328 4329 Column() { 4330 Row() { 4331 Button("Insert Image").onClick () => { 4332 if (this.imagePixelMap !== undefined) { 4333 let imageStyledString = new MutableStyledString(new ImageAttachment({ 4334 value: this.imagePixelMap, 4335 size: { width: 50, height: 50 }, 4336 layoutStyle: { borderRadius: LengthMetrics.vp(10) }, 4337 verticalAlign: ImageSpanAlignment.BASELINE, 4338 objectFit: ImageFit.Contain 4339 })) 4340 // Obtain the styled string displayed in the component. 4341 this.richEditorStyledString = this.controller.getStyledString(); 4342 this.richEditorStyledString.appendStyledString(imageStyledString); 4343 // Display the styled string after the image is inserted on the component. 4344 this.controller.setStyledString(this.richEditorStyledString); 4345 this.controller.setCaretOffset(this.richEditorStyledString.length); 4346 } 4347 }) 4348 Button("Insert Text").onClick () => { 4349 // Obtain the styled string displayed in the component. 4350 this.richEditorStyledString = this.controller.getStyledString(); 4351 this.richEditorStyledString.appendStyledString(this.styledString); 4352 // Display the styled string after the text is inserted on the component. 4353 this.controller.setStyledString(this.richEditorStyledString); 4354 this.controller.setCaretOffset(this.richEditorStyledString.length); 4355 }) 4356 } 4357 Row() { 4358 Button("Get Selection").onClick(() => { 4359 // Obtain the selection. 4360 let richEditorSelection = this.controller.getSelection(); 4361 let start = richEditorSelection.start ? richEditorSelection.start : 0; 4362 let end = richEditorSelection.end ? richEditorSelection.end : 0; 4363 // Obtain the styled string displayed in the component. 4364 this.richEditorStyledString = this.controller.getStyledString(); 4365 this.selection = '[ ' + start + ' , ' + end + ' ]'; 4366 if (start == end) { 4367 this.content = ""; 4368 } else { 4369 this.content = this.richEditorStyledString.subStyledString(start, end - start).getString(); 4370 } 4371 }) 4372 Button("Update Selection Style").onClick () => { 4373 // Obtain the selection. 4374 let richEditorSelection = this.controller.getSelection(); 4375 let start = richEditorSelection.start ? richEditorSelection.start : 0; 4376 let end = richEditorSelection.end ? richEditorSelection.end : 0; 4377 // Obtain the styled string displayed in the component. 4378 this.richEditorStyledString = this.controller.getStyledString(); 4379 this.richEditorStyledString.setStyle({ 4380 start: start, 4381 length: end - start, 4382 styledKey: StyledStringKey.FONT, 4383 styledValue: this.textStyle 4384 }) 4385 // Display the styled string after the style change on the component. 4386 this.controller.setStyledString(this.richEditorStyledString); 4387 }) 4388 Button("Delete Selected").onClick(() => { 4389 // Obtain the selection. 4390 let richEditorSelection = this.controller.getSelection(); 4391 let start = richEditorSelection.start ? richEditorSelection.start : 0; 4392 let end = richEditorSelection.end ? richEditorSelection.end : 0; 4393 // Obtain the styled string displayed in the component. 4394 this.richEditorStyledString = this.controller.getStyledString(); 4395 this.richEditorStyledString.removeString(start, end - start); 4396 // Display the styled string after the content is deleted on the component. 4397 this.controller.setStyledString(this.richEditorStyledString); 4398 }) 4399 } 4400 } 4401 .width("100%") 4402 } 4403 } 4404} 4405``` 4406 4407 4408 4409### Example 21 4410This example shows the usage of **NodeAdapter**. 4411 4412```ts 4413@Entry 4414@Component 4415export struct Index { 4416 @State lineCount: string = "" 4417 @State glyphPositionAtCoordinate: string = "" 4418 @State lineMetrics: string = "" 4419 controller: RichEditorController = new RichEditorController(); 4420 @State textStr: string = 4421 'Hello World!' 4422 4423 build() { 4424 Scroll() { 4425 Column() { 4426 Text('getLayoutManager obtains the layout information relative to the component') 4427 .fontSize(9) 4428 .fontColor(0xCCCCCC) 4429 .width('90%') 4430 .padding(10) 4431 RichEditor({ controller: this.controller }) 4432 .borderColor(Color.Red) 4433 .borderWidth(1) 4434 .onReady(() => { 4435 this.controller.addTextSpan(this.textStr) 4436 }) 4437 .onAreaChange(() => { 4438 let layoutManager = this.controller.getLayoutManager(); 4439 this.lineCount = "LineCount: " + layoutManager.getLineCount() 4440 }) 4441 4442 Text('LineCount').fontSize(9).fontColor(0xCCCCCC).width('90%').padding(10) 4443 Text(this.lineCount) 4444 4445 Text('GlyphPositionAtCoordinate').fontSize(9).fontColor(0xCCCCCC).width('90%').padding(10) 4446 Button("Glyph info of relative component coordinates [150, 50]") 4447 .onClick(() => { 4448 let layoutManager: LayoutManager = this.controller.getLayoutManager() 4449 let position = layoutManager.getGlyphPositionAtCoordinate(150, 50) 4450 this.glyphPositionAtCoordinate = 4451 "Relative component coordinates [150, 50] glyphPositionAtCoordinate position: " + position.position + " affinity: " + 4452 position.affinity 4453 }) 4454 .margin({ bottom: 20, top: 10 }) 4455 Text(this.glyphPositionAtCoordinate) 4456 4457 Text('LineMetrics').fontSize(9).fontColor(0xCCCCCC).width('90%').padding(10) 4458 Button("Line Metrics") 4459 .onClick(() => { 4460 let layoutManager: LayoutManager = this.controller.getLayoutManager() 4461 let lineMetrics = layoutManager.getLineMetrics(0) 4462 this.lineMetrics = "lineMetrics is " + JSON.stringify(lineMetrics) + '\n\n' 4463 let runMetrics = lineMetrics.runMetrics 4464 runMetrics.forEach((value, key) => { 4465 this.lineMetrics += "runMetrics key is " + key + " " + JSON.stringify(value) + "\n\n" 4466 }); 4467 }) 4468 .margin({ bottom: 20, top: 10 }) 4469 Text(this.lineMetrics) 4470 } 4471 .margin({ top: 100, left: 8, right: 8 }) 4472 } 4473 } 4474} 4475``` 4476 4477 4478 4479### Example: 22 4480 4481This example shows how to set **editMenuOptions**. 4482 4483```ts 4484// xxx.ets 4485@Entry 4486@Component 4487struct RichEditorExample { 4488 controller: RichEditorController = new RichEditorController(); 4489 options: RichEditorOptions = { controller: this.controller } 4490 4491 onCreateMenu(menuItems: Array<TextMenuItem>) { 4492 console.log('menuItems size=' + menuItems.length); 4493 menuItems.forEach((value, index) => { 4494 console.log('menuItem' + index + ', id=' + JSON.stringify(value)); 4495 }) 4496 let extensionMenuItems: Array<TextMenuItem> = [ 4497 { 4498 content: 'Extended RichEditor 1', icon: $r('app.media.startIcon'), id: TextMenuItemId.of('extension1') 4499 }, 4500 { 4501 content: 'Extended RichEditor 2', icon: $r('app.media.startIcon'), id: TextMenuItemId.of('extension2') 4502 }, 4503 { 4504 content: 'Extended RichEditor 3', icon: $r('app.media.startIcon'), id: TextMenuItemId.of('extension3') 4505 }, 4506 { 4507 content: 'Extended RichEditor 4', icon: $r('app.media.startIcon'), id: TextMenuItemId.of('extension4') 4508 } 4509 ] 4510 return menuItems.concat(extensionMenuItems) 4511 } 4512 onMenuItemClicked(menuItem: TextMenuItem, textRange: TextRange) { 4513 if (menuItem.id.equals(TextMenuItemId.of('extension1'))) { 4514 console.log('click' + menuItem.content + ', textRange=' + JSON.stringify(textRange)) 4515 return true; 4516 } 4517 return false; 4518 } 4519 4520 build() { 4521 Row() { 4522 RichEditor(this.options) 4523 .onReady(() => { 4524 this.controller.addTextSpan("Extended RichEditor") 4525 }) 4526 .editMenuOptions({ 4527 onCreateMenu: (menuItems: Array<TextMenuItem>) => { 4528 return this.onCreateMenu(menuItems) 4529 }, 4530 onMenuItemClick: (menuItem: TextMenuItem, textRange: TextRange) => { 4531 return this.onMenuItemClicked(menuItem, textRange) 4532 } 4533 }) 4534 .height(200) 4535 .borderWidth(1) 4536 .borderColor(Color.Red) 4537 } 4538 } 4539} 4540``` 4541 4542 4543 4544<!--no_check-->