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