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