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