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