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