• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# RichEditor
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @carnivore233-->
5<!--Designer: @pssea-->
6<!--Tester: @mateng_Holtens-->
7<!--Adviser: @HelloCrease-->
8
9支持图文混排和文本交互式编辑的组件。
10
11>  **说明:**
12>
13>  该组件从API version 10开始支持。后续版本新增内容,采用上角标单独标记该内容的起始版本。
14
15
16## 子组件
17
18不包含子组件。
19
20
21## 接口
22
23### RichEditor
24
25RichEditor(value: RichEditorOptions)
26
27**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
28
29**系统能力:** SystemCapability.ArkUI.ArkUI.Full
30
31**参数:**
32
33| 参数名   | 类型                                    | 必填   | 说明        |
34| ----- | --------------------------------------- | ---- | ----------- |
35| value | [RichEditorOptions](#richeditoroptions) | 是    | 富文本组件初始化选项。 |
36
37### RichEditor<sup>12+</sup>
38
39RichEditor(options: RichEditorStyledStringOptions)
40
41**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
42
43**系统能力:** SystemCapability.ArkUI.ArkUI.Full
44
45**参数:**
46
47| 参数名   | 类型                                    | 必填   | 说明        |
48| ----- | --------------------------------------- | ---- | ----------- |
49| options | [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) | 是    | 富文本组件初始化选项。 |
50
51## 属性
52
53除支持[通用属性](ts-component-general-attributes.md)外,还支持以下属性:
54
55>  **说明:**
56>
57>  align属性只支持上方、中间和下方位置的对齐方式。
58>
59>  不支持[borderImage](ts-universal-attributes-border-image.md#borderimage)属性。
60
61### customKeyboard
62
63customKeyboard(value: CustomBuilder, options?: KeyboardOptions)
64
65设置自定义键盘。
66
67当设置自定义键盘时,输入框激活后不会打开系统输入法,而是加载指定的自定义组件。
68
69自定义键盘的高度可以通过自定义组件根节点的height属性设置,宽度不可设置,使用系统默认值。
70
71自定义键盘无法获取焦点,但是会拦截手势事件。
72
73默认在输入控件失去焦点时,关闭自定义键盘。
74
75如果设备支持拍摄输入,设置自定义键盘后,该输入框会不支持拍摄输入。
76
77**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
78
79**系统能力:** SystemCapability.ArkUI.ArkUI.Full
80
81**参数:**
82
83| 参数名                | 类型                                        | 必填 | 说明                             |
84| --------------------- | ------------------------------------------- | ---- | -------------------------------- |
85| value                 | [CustomBuilder](ts-types.md#custombuilder8) | 是   | 自定义键盘。                     <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
86| options<sup>12+</sup> | [KeyboardOptions](#keyboardoptions12)       | 否   | 设置自定义键盘是否支持避让功能。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
87
88### bindSelectionMenu
89
90bindSelectionMenu(spanType: RichEditorSpanType, content: CustomBuilder, responseType: ResponseType | RichEditorResponseType,
91    options?: SelectionMenuOptions)
92
93设置自定义选择菜单。自定义菜单超长时,建议内部嵌套[Scroll](./ts-container-scroll.md)组件使用,避免键盘被遮挡。
94
95**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
96
97**系统能力:** SystemCapability.ArkUI.ArkUI.Full
98
99**参数:**
100
101| 参数名       | 类型                                                         | 必填 | 说明                                                      |
102| ------------ | ------------------------------------------------------------ | ---- | --------------------------------------------------------- |
103| spanType     | [RichEditorSpanType](#richeditorspantype)                    | 是   | 菜单的类型。<br/>默认值:<br/>RichEditorSpanType.TEXT    |
104| content      | [CustomBuilder](ts-types.md#custombuilder8)                  | 是   | 菜单的内容。                                              |
105| responseType | &nbsp;[ResponseType](ts-appendix-enums.md#responsetype8)&nbsp; \| &nbsp;[RichEditorResponseType](#richeditorresponsetype11) | 是   | 菜单的响应类型。<br/> 默认值:<br/>ResponseType.LongPress |
106| options      | [SelectionMenuOptions](#selectionmenuoptions)              | 否   | 菜单的选项。                                              |
107
108### copyOptions
109
110copyOptions(value: CopyOptions)
111
112设置组件是否支持文本内容可复制粘贴。
113
114从API version 20开始,RichEditor组件在执行复制或剪切操作时,会将HTML格式的内容添加到剪贴板中。
115
116- 仅支持TextSpan和ImageSpan向剪贴板中添加HTML内容,其他Span类型(如BuilderSpan、SymbolSpan、CustomSpan)则不能添加。
117
118- 设置RichEditor组件的属性字符串时,请参考属性字符串[toHtml](ts-universal-styled-string.md#tohtml14)接口文档,以了解支持转换为HTML的范围。
119
120copyOptions不为CopyOptions.None时,长按组件内容,会弹出文本选择菜单。如果通过bindSelectionMenu等方式自定义文本选择菜单,则会弹出自定义的菜单。
121
122设置copyOptions为CopyOptions.None时,禁用复制、剪切、翻译、分享、搜索、帮写功能,且不支持拖拽操作。
123
124**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
125
126**系统能力:** SystemCapability.ArkUI.ArkUI.Full
127
128**参数:**
129
130| 参数名 | 类型                                             | 必填 | 说明                                                         |
131| ------ | ------------------------------------------------ | ---- | ------------------------------------------------------------ |
132| value  | [CopyOptions](ts-appendix-enums.md#copyoptions9) | 是   | 组件支持文本内容是否可复制粘贴。<br/>默认值:CopyOptions.LocalDevice |
133
134### enableDataDetector<sup>11+</sup>
135
136enableDataDetector(enable: boolean)
137
138设置是否进行文本特殊实体识别。
139
140该接口依赖设备底层应具有文本识别能力,否则设置不会生效。
141
142当enableDataDetector设置为true且未指定[dataDetectorConfig](#datadetectorconfig11)属性时,系统将默认识别所有类型的实体,并将这些实体的color和decoration更改为预设样式:
143
144```ts
145color: '#ff007dff'
146decoration:{
147  type: TextDecorationType.Underline,
148  color: '#ff007dff',
149  style: TextDecorationStyle.SOLID
150}
151```
152
153触摸点击或鼠标右键点击实体时,会根据实体类型弹出对应的实体操作菜单,鼠标左键点击实体会直接响应菜单的第一个选项。
154
155对addBuilderSpan的节点文本,该功能不会生效。
156
157当copyOptions设置为CopyOptions.None时,点击实体弹出的菜单没有选择文本和复制功能。
158<!--RP1--><!--RP1End-->
159
160**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
161
162**系统能力:** SystemCapability.ArkUI.ArkUI.Full
163
164**参数:**
165
166| 参数名 | 类型    | 必填 | 说明                              |
167| ------ | ------- | ---- | --------------------------------- |
168| enable  | boolean | 是   | 使能文本识别。<br/>true表示使能文本特殊实体识别,false表示不使能文本特殊实体识别。<br/>默认值: false |
169
170### dataDetectorConfig<sup>11+</sup>
171
172dataDetectorConfig(config: TextDataDetectorConfig)
173
174设置文本特殊实体识别配置,可配置识别类型、实体显示样式,并可选择是否开启长按预览功能。
175
176需配合[enableDataDetector](#enabledatadetector11)一起使用,设置enableDataDetector为true时,dataDetectorConfig的配置才能生效。
177
178当有两个实体A、B重叠时,按以下规则保留实体:
179
1801.&nbsp;若A&nbsp;⊂&nbsp;B,则保留B,反之则保留A。
181
1822.&nbsp;当A&nbsp;⊄&nbsp;B且B&nbsp;⊄&nbsp;A时,若A.start&nbsp;<&nbsp;B.start,则保留A,反之则保留B。
183
184**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
185
186**系统能力:** SystemCapability.ArkUI.ArkUI.Full
187
188**参数:**
189
190| 参数名 | 类型                                                        | 必填 | 说明                                                         |
191| ------ | ----------------------------------------------------------- | ---- | ------------------------------------------------------------ |
192| config | [TextDataDetectorConfig](ts-text-common.md#textdatadetectorconfig11对象说明) | 是   | 文本识别配置。|
193
194### enablePreviewText<sup>12+</sup>
195
196enablePreviewText(enable: boolean)
197
198设置是否开启预上屏功能。
199
200**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
201
202**系统能力:** SystemCapability.ArkUI.ArkUI.Full
203
204**参数:**
205
206| 参数名 | 类型    | 必填 | 说明                              |
207| ------ | ------- | ---- | --------------------------------- |
208| enable  | boolean | 是   | 使能预上屏功能。<br/>true表示开启,false表示不开启。<br/>默认值: true |
209
210>  **说明:**
211>
212该接口在CAPI场景使用时默认关闭。可以在工程的module.json5中配置[metadata](../../../../application-dev/quick-start/module-structure.md#metadata对象内部结构)字段控制是否启用预上屏,配置如下:
213> ```json
214> "metadata": [
215>  {
216>     "name": "can_preview_text",
217>     "value": "true",
218>  }
219> ]
220> ```
221
222### placeholder<sup>12+</sup>
223
224placeholder(value: ResourceStr, style?: PlaceholderStyle)
225
226设置无输入时的提示文本。
227
228**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
229
230**系统能力:** SystemCapability.ArkUI.ArkUI.Full
231
232**参数:**
233
234| 参数名 | 类型                                    | 必填 | 说明                                                    |
235| ------ | --------------------------------------- | ---- | ------------------------------------------------------- |
236| value  | [ResourceStr](ts-types.md#resourcestr)  | 是   | 无输入时的提示文本。                                    |
237| style  | [PlaceholderStyle](#placeholderstyle12) | 否   | 提示文本的字体样式。<br/>缺省时默认跟随主题。 |
238
239### caretColor<sup>12+</sup>
240
241caretColor(value: ResourceColor)
242
243设置输入框光标、手柄颜色。
244
245**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
246
247**系统能力:** SystemCapability.ArkUI.ArkUI.Full
248
249**参数:**
250
251| 参数名 | 类型                                       | 必填 | 说明                                   |
252| ------ | ------------------------------------------ | ---- | -------------------------------------- |
253| value  | [ResourceColor](ts-types.md#resourcecolor) | 是   | 输入框光标、手柄颜色。<br/>默认值:'#007DFF' |
254
255### selectedBackgroundColor<sup>12+</sup>
256
257selectedBackgroundColor(value: ResourceColor)
258
259设置文本选中的底板颜色。如果未设置不透明度,默认为20%不透明度。
260
261**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
262
263**系统能力:** SystemCapability.ArkUI.ArkUI.Full
264
265**参数:**
266
267| 参数名 | 类型                                       | 必填 | 说明                                       |
268| ------ | ------------------------------------------ | ---- | ------------------------------------------ |
269| value  | [ResourceColor](ts-types.md#resourcecolor) | 是   | 文本选中的底板颜色。<br/>默认为20%不透明度。 |
270
271### editMenuOptions<sup>12+</sup>
272
273editMenuOptions(editMenu: EditMenuOptions)
274
275设置系统默认菜单的扩展项,允许配置扩展项的文本内容、图标和回调方法。
276
277调用[disableMenuItems](../arkts-apis-uicontext-textmenucontroller.md#disablemenuitems20)或[disableSystemServiceMenuItems](../arkts-apis-uicontext-textmenucontroller.md#disablesystemservicemenuitems20)接口屏蔽文本选择菜单内的系统服务菜单项时,editMenuOptions接口内回调方法[onCreateMenu](./ts-text-common.md#oncreatemenu12)的入参列表中不包含被屏蔽的菜单选项。
278
279**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
280
281**系统能力:** SystemCapability.ArkUI.ArkUI.Full
282
283**参数:**
284
285| 参数名 | 类型                                          | 必填 | 说明                                          |
286| ------ | --------------------------------------------- | ---- | --------------------------------------------- |
287| editMenu  | [EditMenuOptions](ts-text-common.md#editmenuoptions) | 是   | 扩展菜单选项。 |
288
289### enterKeyType<sup>12+</sup>
290
291enterKeyType(value: EnterKeyType)
292
293设置软键盘输入法回车键类型。
294
295**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
296
297**系统能力:** SystemCapability.ArkUI.ArkUI.Full
298
299**参数:**
300
301| 参数名 | 类型   | 必填 | 说明                                |
302| ------ | ------ | ---- | ----------------------------------- |
303| value  | [EnterKeyType](ts-basic-components-textinput.md#enterkeytype枚举说明) | 是   | 软键盘输入法回车键类型。<br/>默认为EnterKeyType.NEW_LINE。 |
304
305### enableKeyboardOnFocus<sup>12+</sup>
306
307enableKeyboardOnFocus(isEnabled: boolean)
308
309设置RichEditor通过点击以外的方式获焦时,是否主动拉起软键盘。
310
311
312**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
313
314**系统能力:** SystemCapability.ArkUI.ArkUI.Full
315
316**参数:**
317
318| 参数名 | 类型 | 必填 | 说明 |
319| ------ | ------- | ---- | ----------------------------------------------------------- |
320| isEnabled  | boolean | 是   | 通过点击以外的方式获焦时,是否主动拉起软键盘。<br/>true表示主动拉起软键盘,false表示不主动拉起软键盘。<br/>默认值: true |
321
322### barState<sup>13+</sup>
323
324barState(state: BarState)
325
326设置RichEditor滚动条的显示模式。
327
328**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。
329
330**系统能力:** SystemCapability.ArkUI.ArkUI.Full
331
332**参数:**
333
334| 参数名 | 类型 | 必填 | 说明 |
335| ------ | ----------------------------------------- | ---- | ------------------------------------------------------ |
336| state | [BarState](ts-appendix-enums.md#barstate) | 是   | 输入框滚动条的显示模式。<br/>默认值:BarState.Auto |
337
338### maxLength<sup>18+</sup>
339
340maxLength(maxLength: Optional\<number\>)
341
342设置组件内容的最大长度。当内容(包含文本、图片、Symbol和Builder)的总长度达到此值时,将无法继续添加内容。
343
344**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
345
346**系统能力:** SystemCapability.ArkUI.ArkUI.Full
347
348**参数:**
349
350| 参数名 | 类型   | 必填 | 说明                                                         |
351| ------ | ------ | ---- | ------------------------------------------------------------ |
352| maxLength  | [Optional](ts-universal-attributes-custom-property.md#optionalt12)\<number> | 是   | 文本的最大输入字符数。<br/>默认值:Infinity,可以无限输入,支持undefined类型。<br/>**说明:** <br/>当不设置该属性或设置异常值时,取默认值,设置小数时,取整数部分。 |
353
354### maxLines<sup>18+</sup>
355
356maxLines(maxLines: Optional\<number\>)
357
358设置富文本可显示的最大行数。maxLines为可显示行数,当设置maxLines时,超出内容可滚动显示。同时设置组件高度和最大行数,组件高度优先生效。
359
360**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
361
362**系统能力:** SystemCapability.ArkUI.ArkUI.Full
363
364**参数:**
365
366| 参数名 | 类型                                      | 必填 | 说明                                                         |
367| ------ | ----------------------------------------- | ---- | ------------------------------------------------------------ |
368| maxLines  | [Optional](ts-universal-attributes-custom-property.md#optionalt12)\<number> | 是   | 设置富文本可显示的最大行数。maxLines为可显示行数,当设置maxLines时,超出内容可滚动显示。同时设置组件高度和最大行数,组件高度优先生效。<br/>默认值:Infinity,可以无限输入,支持undefined类型。 <br/>取值范围:(0, +∞) |
369
370### enableHapticFeedback<sup>13+</sup>
371
372enableHapticFeedback(isEnabled: boolean)
373
374设置RichEditor是否支持触感反馈。
375
376**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。
377
378**系统能力:** SystemCapability.ArkUI.ArkUI.Full
379
380**参数:**
381
382| 参数名 | 类型                                          | 必填  | 说明                                                                                  |
383| ------ | --------------------------------------------- |-----|-------------------------------------------------------------------------------------|
384| isEnabled | boolean | 是 | 控制触感反馈的开关。<br/>默认值:true。true表示开启触感反馈,false表示关闭触感反馈。<br/>**说明:**<br/>触感反馈需应用具备ohos.permission.VIBRATE权限,用户已启用触感反馈,且系统硬件支持时才会生效。 |
385
386### keyboardAppearance<sup>15+</sup>
387
388keyboardAppearance(appearance: Optional\<KeyboardAppearance\>)
389
390设置键盘外观。
391
392**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。
393
394**系统能力:** SystemCapability.ArkUI.ArkUI.Full
395
396**参数:**
397
398| 参数名 | 类型 | 必填 | 说明 |
399| ------ | ----------------------------------------- | ---- | ------------------------------------------------------ |
400| appearance | [Optional](ts-universal-attributes-custom-property.md#optionalt12)\<[KeyboardAppearance](ts-text-common.md#keyboardappearance15枚举说明)\> | 是   | 键盘外观。<br/>默认值:KeyboardAppearance.NONE_IMMERSIVE |
401
402### stopBackPress<sup>18+</sup>
403
404stopBackPress(isStopped: Optional&lt;boolean&gt;)
405
406设置是否阻止返回键传递。
407
408**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
409
410**系统能力:** SystemCapability.ArkUI.ArkUI.Full
411
412**参数:**
413
414| 参数名 | 类型                                          | 必填  | 说明                                                                                  |
415| ------ | --------------------------------------------- |-----|-------------------------------------------------------------------------------------|
416| isStopped  | [Optional](ts-universal-attributes-custom-property.md#optionalt12)&lt;boolean&gt; | 是   | 是否阻止返回键。<br/>默认值:true,true表示阻止返回键,false表示不阻止返回键。<br/>**说明:** <br/>当不设置该属性或设置异常值时,取默认值。|
417
418### undoStyle<sup>20+</sup>
419
420undoStyle(style: Optional&lt;UndoStyle&gt;)
421
422设置撤销还原时是否保留原内容的样式。
423
424使用[RichEditorStyledStringOptions](#richeditorstyledstringoptions12)构建RichEditor组件时,撤销还原时默认保留原内容样式,不受该接口设置的属性影响。
425
426**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。
427
428**系统能力:** SystemCapability.ArkUI.ArkUI.Full
429
430**参数:**
431
432| 参数名 | 类型                                          | 必填  | 说明                                                                                  |
433| ------ | --------------------------------------------- |-----|-------------------------------------------------------------------------------------|
434| style  | [Optional](ts-universal-attributes-custom-property.md#optionalt12)&lt;[UndoStyle](#undostyle20-1)&gt; | 是   | 撤销还原是否保留原样式选项。默认值:UndoStyle.CLEAR_STYLE |
435
436### enableAutoSpacing<sup>20+</sup>
437
438enableAutoSpacing(enable: Optional\<boolean>)
439
440设置是否开启中文与西文的自动间距。
441
442**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。
443
444**系统能力:** SystemCapability.ArkUI.ArkUI.Full
445
446**参数:**
447
448| 参数名 | 类型    | 必填 | 说明                               |
449| ------ | ------- | ---- | ---------------------------------- |
450| enable | [Optional](ts-universal-attributes-custom-property.md#optionalt12)\<boolean> | 是   | 是否开启中文与西文的自动间距。<br/>true为开启自动间距,false为不开启。<br />默认值:false |
451
452## 事件
453
454除支持[通用事件](ts-component-general-events.md)外,还支持[OnDidChangeCallback](ts-text-common.md#ondidchangecallback12)、[StyledStringChangedListener](ts-text-common.md#styledstringchangedlistener12)、[StyledStringChangeValue](ts-text-common.md#styledstringchangevalue12)和以下事件:
455
456### onReady
457
458onReady(callback:Callback\<void\>)
459
460富文本组件初始化完成后触发回调。
461
462**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
463
464**系统能力:** SystemCapability.ArkUI.ArkUI.Full
465
466**参数:**
467
468| 参数名   | 类型                                    | 必填   | 说明        |
469| ----- | --------------------------------------- | ---- | ----------- |
470| callback |Callback\<void\> | 是    | 订阅富文本组件初始化完成的回调。 |
471
472### onSelect
473
474onSelect(callback:Callback\<[RichEditorSelection](#richeditorselection)\>)
475
476鼠标左键双击选中内容触发回调;松开鼠标左键再次触发回调。
477
478手指长按选中内容触发回调;松开手指再次触发回调。
479
480通过手指或鼠标连续修改选中区、三击选段场景,不回调onSelect。
481
482需要实时感知选中区变化的场景和使用[RichEditorStyledStringOptions](#richeditorstyledstringoptions12)构建的RichEditor组件,请使用onSelectionChange接口。
483
484**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
485
486**系统能力:** SystemCapability.ArkUI.ArkUI.Full
487
488**参数:**
489
490| 参数名 | 类型                                        | 必填 | 说明                 |
491| ------ | ------------------------------------------- | ---- | -------------------- |
492| callback | Callback\<[RichEditorSelection](#richeditorselection)\> | 是   | [RichEditorSelection](#richeditorselection)为选中的所有span信息。<br/>选择时触发的回调。 |
493
494### aboutToIMEInput
495
496aboutToIMEInput(callback:Callback\<[RichEditorInsertValue](#richeditorinsertvalue), boolean\>)
497
498输入法输入内容前触发回调。
499
500使用[RichEditorStyledStringOptions](#richeditorstyledstringoptions12)构建的RichEditor组件不支持该回调。
501
502**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
503
504**系统能力:** SystemCapability.ArkUI.ArkUI.Full
505
506**参数:**
507
508| 参数名 | 类型                                        | 必填 | 说明                 |
509| ------ | ------------------------------------------- | ---- | -------------------- |
510| callback | Callback\<[RichEditorInsertValue](#richeditorinsertvalue), boolean\> | 是   | [RichEditorInsertValue](#richeditorinsertvalue)为输入法将要输入内容信息。<br/>true:组件执行添加内容操作。<br/>false:组件不执行添加内容操作。<br/>输入法输入内容前的回调。|
511
512### onDidIMEInput<sup>12+</sup>
513
514onDidIMEInput(callback:Callback\<TextRange>)
515
516输入法输入完成后,触发回调。
517
518使用[RichEditorStyledStringOptions](#richeditorstyledstringoptions12)构建的RichEditor组件不支持该回调。
519
520**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
521
522**系统能力:** SystemCapability.ArkUI.ArkUI.Full
523
524**参数:**
525
526| 参数名 | 类型                                        | 必填 | 说明                 |
527| ------ | ------------------------------------------- | ---- | -------------------- |
528| callback | Callback\<[TextRange](ts-text-common.md#textrange12)\> | 是 | TextRange为输入法本次输入内容的范围。<br/>输入法完成输入时的回调。|
529
530
531### onIMEInputComplete
532
533onIMEInputComplete(callback:Callback\<[RichEditorTextSpanResult](#richeditortextspanresult)\>)
534
535输入法输入完成后,触发回调。
536
537该接口仅支持返回一个文本span的信息,当编辑操作涉及返回多个文本span信息时,建议使用[onDidIMEInput](#ondidimeinput12)接口。
538
539使用[RichEditorStyledStringOptions](#richeditorstyledstringoptions12)构建的RichEditor组件不支持该回调。
540
541**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
542
543**系统能力:** SystemCapability.ArkUI.ArkUI.Full
544
545**参数:**
546
547| 参数名 | 类型                                        | 必填 | 说明                 |
548| ------ | ------------------------------------------- | ---- | -------------------- |
549| callback | Callback\<[RichEditorTextSpanResult](#richeditortextspanresult)\> | 是 | [RichEditorTextSpanResult](#richeditortextspanresult)为输入法完成输入后的文本Span信息。<br/>输入法完成输入后的回调。|
550
551### aboutToDelete
552
553aboutToDelete(callback:Callback\<[RichEditorDeleteValue](#richeditordeletevalue), boolean\>)
554
555输入法删除内容前,触发回调。
556
557使用[RichEditorStyledStringOptions](#richeditorstyledstringoptions12)构建的RichEditor组件不支持该回调。
558
559**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
560
561**系统能力:** SystemCapability.ArkUI.ArkUI.Full
562
563**参数:**
564
565| 参数名 | 类型                                        | 必填 | 说明                 |
566| ------ | ------------------------------------------- | ---- | -------------------- |
567| callback | Callback\<[RichEditorDeleteValue](#richeditordeletevalue), boolean\> | 是 | [RichEditorDeleteValue](#richeditordeletevalue)为准备删除的内容所在的文本或者图片Span信息。<br/>true:组件执行删除操作。<br/>false:组件不执行删除操作。<br/>输入法删除内容前的回调,英文预上屏点击候选词时会执行该回调。|
568
569### onDeleteComplete
570
571onDeleteComplete(callback:Callback\<void\>)
572
573输入法删除内容后,触发回调。
574
575使用[RichEditorStyledStringOptions](#richeditorstyledstringoptions12)构建的RichEditor组件不支持该回调。
576
577**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
578
579**系统能力:** SystemCapability.ArkUI.ArkUI.Full
580
581**参数:**
582
583| 参数名   | 类型                                    | 必填   | 说明        |
584| ----- | --------------------------------------- | ---- | ----------- |
585| callback |Callback\<void\> | 是    | 订阅输入法完成删除内容的回调。 |
586
587### onPaste<sup>11+</sup>
588
589onPaste(callback: [PasteEventCallback](#pasteeventcallback12) )
590
591粘贴时,触发回调。开发者可以通过该方法,覆盖系统默认行为,实现图文的粘贴。
592
593**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
594
595**系统能力:** SystemCapability.ArkUI.ArkUI.Full
596
597**参数:**
598
599| 参数名 | 类型    | 必填 | 说明                          |
600| ------ | ------- | ---- | ----------------------------- |
601| callback | [PasteEventCallback](#pasteeventcallback12) | 是   | 订阅粘贴时的回调。 |
602
603### onSelectionChange<sup>12+</sup>
604
605onSelectionChange(callback:Callback\<[RichEditorRange](#richeditorrange)\>)
606
607内容选择区域或编辑状态下的光标位置发生变化时,将触发该回调。光标位置变化时,回调中选择区域的起始和终止位置相等。
608
609**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
610
611**系统能力:** SystemCapability.ArkUI.ArkUI.Full
612
613**参数:**
614
615| 参数名   | 类型                                    | 必填   | 说明        |
616| ----- | --------------------------------------- | ---- | ----------- |
617| callback |Callback\<[RichEditorRange](#richeditorrange)\> | 是    | [RichEditorRange](#richeditorrange)为所有内容的选择区域起始和终止位置。<br/>订阅文本选择区域发生变化或编辑状态下光标位置发生变化时触发的回调。|
618
619### onEditingChange<sup>12+</sup>
620
621onEditingChange(callback: Callback\<boolean\>)
622
623组件内容的编辑状态发生变化时触发该回调函数。
624
625**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
626
627**系统能力:** SystemCapability.ArkUI.ArkUI.Full
628
629**参数:**
630
631| 参数名   | 类型                                    | 必填   | 说明        |
632| ----- | --------------------------------------- | ---- | ----------- |
633| callback | Callback\<boolean\> | 是    | true表示编辑态,false表示非编辑态。 |
634
635### onSubmit<sup>12+</sup>
636
637onSubmit(callback: SubmitCallback)
638
639按下软键盘输入法回车键时触发该回调。
640
641**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
642
643**系统能力:** SystemCapability.ArkUI.ArkUI.Full
644
645**参数:**
646
647| 参数名 | 类型    | 必填 | 说明                          |
648| ------ | ------- | ---- | ----------------------------- |
649| callback | [SubmitCallback](#submitcallback12) | 是   | 订阅事件的回调。 |
650
651### onWillChange<sup>12+</sup>
652
653onWillChange(callback: Callback\<[RichEditorChangeValue](#richeditorchangevalue12) , boolean\>)
654
655在组件执行增删操作前,触发回调。
656
657使用[RichEditorStyledStringOptions](#richeditorstyledstringoptions12)构建的RichEditor组件不支持该回调。
658
659**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
660
661**系统能力:** SystemCapability.ArkUI.ArkUI.Full
662
663**参数:**
664
665| 参数名 | 类型 | 必填 | 说明 |
666| -- | -- | -- | -- |
667| callback | Callback\<[RichEditorChangeValue](#richeditorchangevalue12) , boolean\> | 是    | [RichEditorChangeValue](#richeditorchangevalue12)为图文变化信息;boolean表示当前图文是否允许被更改,true:允许图文被更改;false:不允许图文被更改。 |
668
669### onDidChange<sup>12+</sup>
670
671onDidChange(callback: OnDidChangeCallback)
672
673在组件执行增删操作后,触发回调。如果文本实际未发生增删,则不触发该回调。
674
675使用[RichEditorStyledStringOptions](#richeditorstyledstringoptions12)构建的RichEditor组件不支持该回调。
676
677**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
678
679**系统能力:** SystemCapability.ArkUI.ArkUI.Full
680
681**参数:**
682
683| 参数名 | 类型 | 必填 | 说明 |
684| -- | -- | -- | -- |
685| callback | [OnDidChangeCallback](ts-text-common.md#ondidchangecallback12) | 是 | 图文变化前后的内容范围。 |
686
687### onCut<sup>12+</sup>
688
689onCut(callback: Callback\<CutEvent\>)
690
691剪切时触发回调。开发者可以通过该方法,覆盖系统默认行为,实现图文的剪切。
692
693使用[RichEditorStyledStringOptions](#richeditorstyledstringoptions12)构建的RichEditor组件,默认支持图文的剪切。
694
695**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
696
697**系统能力:** SystemCapability.ArkUI.ArkUI.Full
698
699**参数:**
700
701| 参数名   | 类型                                    | 必填   | 说明        |
702| ----- | --------------------------------------- | ---- | ----------- |
703| callback |Callback\<[CutEvent](#cutevent12)\> | 是    | 定义用户剪切事件。 |
704
705### onCopy<sup>12+</sup>
706
707onCopy(callback: Callback\<CopyEvent\>)
708
709复制时触发回调。开发者可以通过该方法,覆盖系统默认行为,实现图文的复制。
710
711使用[RichEditorStyledStringOptions](#richeditorstyledstringoptions12)构建的RichEditor组件,默认支持图文的复制。
712
713**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
714
715**系统能力:** SystemCapability.ArkUI.ArkUI.Full
716
717**参数:**
718
719| 参数名   | 类型                                    | 必填   | 说明        |
720| ----- | --------------------------------------- | ---- | ----------- |
721| callback |Callback\<[CopyEvent](#copyevent12)\> | 是    | 定义用户复制事件。 |
722
723## RichEditorInsertValue
724
725插入文本的信息。
726
727**系统能力:** SystemCapability.ArkUI.ArkUI.Full
728
729| 名称           | 类型      | 只读 | 可选   | 说明         |
730| ------------ | ------ | ---- | ----|------ |
731| insertOffset | number | 否| 否    | 插入的文本偏移位置。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
732| insertValue  | string | 否| 否    | 插入的文本内容。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。  |
733| previewText<sup>12+</sup> | string | 否| 是    | 插入的预上屏文本内容。<br/> **原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
734
735
736## RichEditorDeleteValue
737
738删除操作和被删除内容的信息。
739
740**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
741
742**系统能力:** SystemCapability.ArkUI.ArkUI.Full
743
744| 名称                    | 类型                                        | 只读 | 可选   | 说明                  |
745| --------------------- | ---------------------------------------- | ---- | -----|-------------- |
746| offset                | number                                   | 否 | 否    | 删除内容的偏移位置。          |
747| direction             | [RichEditorDeleteDirection](#richeditordeletedirection) | 否 | 否    | 删除操作的方向。            |
748| length                | number                                   | 否 | 否    | 删除内容长度。             |
749| richEditorDeleteSpans | Array<[RichEditorTextSpanResult](#richeditortextspanresult) \| [RichEditorImageSpanResult](#richeditorimagespanresult)> | 否 | 否    | 删除的文本或图片Span的信息。 |
750
751
752## RichEditorDeleteDirection
753
754删除方向。
755
756**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
757
758**系统能力:** SystemCapability.ArkUI.ArkUI.Full
759
760| 名称     | 说明       |
761| -------- | ---------- |
762| BACKWARD | 向后删除。 |
763| FORWARD  | 向前删除。 |
764
765
766## RichEditorTextSpanResult
767
768文本Span信息。
769
770**系统能力:** SystemCapability.ArkUI.ArkUI.Full
771
772| 名称                            | 类型                                          | 只读 | 可选   | 说明                     |
773| ----------------------------- | ---------------------------------------- | ---- | ------------|---------- |
774| spanPosition                  | [RichEditorSpanPosition](#richeditorspanposition) | 否 | 否    | Span位置。                <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
775| value                         | string                                    | 否 | 否    | 文本Span内容或Symbol的id。              <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
776| textStyle                     | [RichEditorTextStyleResult](#richeditortextstyleresult)  | 否 | 否   | 文本Span样式信息。            <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
777| offsetInSpan                  | [number, number]                          | 否 | 否    | 文本Span内容里有效内容的起始和结束位置。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
778| valueResource<sup>11+</sup>   | [Resource](ts-types.md#resource)          | 否 | 是    | 组件SymbolSpan内容。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。        |
779| symbolSpanStyle<sup>11+</sup> | [RichEditorSymbolSpanStyle](#richeditorsymbolspanstyle11)  | 否 | 是    | 组件SymbolSpan样式信息。      <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
780| paragraphStyle<sup>12+</sup>  | [RichEditorParagraphStyle](#richeditorparagraphstyle11)   | 否 | 是   | 段落样式。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
781| previewText<sup>12+</sup>      | string                                    | 否 | 是    | 文本Span预上屏内容。              <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
782| urlStyle<sup>19+</sup>  | [RichEditorUrlStyle](#richeditorurlstyle19)    | 否 | 是   | url信息。<br/>默认值:undefined <br/>**原子化服务API:** 从API version 19开始,该接口支持在原子化服务中使用。|
783
784
785## RichEditorSpanPosition
786
787Span位置信息。
788
789**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
790
791**系统能力:** SystemCapability.ArkUI.ArkUI.Full
792
793| 名称        | 类型           | 只读 | 可选   | 说明                          |
794| --------- | ---------------- |----| ---- | --------------------------- |
795| spanIndex | number           | 否 | 否    | Span索引值。                    |
796| spanRange | [number, number] | 否 | 否    | Span内容在RichEditor内的起始和结束位置。 |
797
798## RichEditorSpanType
799
800Span类型信息。
801
802**系统能力:** SystemCapability.ArkUI.ArkUI.Full
803
804| 名称    | 值     | 说明         |
805| ----- | ---- | ------------ |
806| TEXT  | 0 | Span类型为文字。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。  |
807| IMAGE | 1 | Span类型为图像。  <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。   |
808| MIXED | 2 | Span类型为图文混合。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。  |
809| BUILDER<sup>12+</sup> | 3 | Span类型为BuilderSpan。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。  |
810| DEFAULT<sup>15+</sup> | 4 | 注册此类型的菜单,但未注册TEXT、IMAGE、MIXED、BUILDER菜单时,文字类型、图像类型、图文混合类型、BuilderSpan类型都会触发并显示此类型对应的菜单。 <br/>**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。|
811
812## RichEditorResponseType<sup>11+</sup>
813
814菜单的响应类型。
815
816**系统能力:** SystemCapability.ArkUI.ArkUI.Full
817
818| 名称    | 值     | 说明         |
819| ----- | ---- | ------------ |
820| RIGHT_CLICK  | 0 | 通过鼠标右键触发菜单弹出。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。   |
821| LONG_PRESS | 1 | 通过长按触发菜单弹出。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。   |
822| SELECT | 2 | 通过鼠标选中触发菜单弹出。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。  |
823| DEFAULT<sup>15+</sup> | 3 | 注册此响应类型的菜单,但未注册RIGHT_CLICK、LONG_PRESS、SELECT响应类型的菜单时,通过鼠标右键、长按、鼠标选中都会触发菜单弹出。 <br/>**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。  |
824
825## UndoStyle<sup>20+</sup>
826
827撤销还原是否保留原样式选项。
828
829**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。
830
831**系统能力:** SystemCapability.ArkUI.ArkUI.Full
832
833| 名称    | 值     | 说明         |
834| ----- | ---- | ------------ |
835| CLEAR_STYLE  | 0 | 撤销还原内容不保留原样式。   |
836| KEEP_STYLE | 1 | 撤销还原内容保留原样式。   |
837
838## RichEditorTextStyleResult
839
840后端返回的文本样式信息。
841
842**系统能力:** SystemCapability.ArkUI.ArkUI.Full
843
844| 名称         | 类型                                        | 只读 | 可选   | 说明           |
845| ---------- | ---------------------------------------- | ---- | -------|----- |
846| fontColor  | [ResourceColor](ts-types.md#resourcecolor) | 否| 否    | 文本颜色。        <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
847| fontSize   | number                                   | 否| 否    | 字体大小,默认单位为fp。        <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
848| fontStyle  | [FontStyle](ts-appendix-enums.md#fontstyle) | 否| 否    | 字体样式。        <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
849| fontWeight | number                                   | 否| 否    | 字体粗细。        <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
850| fontFamily | string                                   | 否| 否    | 字体列表。        <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
851| decoration | [DecorationStyleResult](ts-text-common.md#decorationstyleresult12) | 否| 否    | 文本装饰线样式信息。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
852| textShadow<sup>12+</sup> | &nbsp;Array&lt;[ShadowOptions](ts-universal-attributes-image-effect.md#shadowoptions对象说明)> | 否| 是    | 文字阴影效果。<br/>**说明:**<br/>仅支持查询阴影模糊半径、颜色和偏移量。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
853| lineHeight<sup>12+</sup> | number       | 否| 是    | 文本行高,默认单位为fp。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
854| letterSpacing<sup>12+</sup>| number       | 否 | 是    | 文本字符间距,默认单位为fp。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
855| fontFeature<sup>12+</sup> | string | 否| 是 | 文字特性效果。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
856| halfLeading<sup>18+</sup> | boolean  | 否 | 是 | 文本是否将行间距平分至行的顶部与底部。<br/>true表示将行间距平分至行的顶部与底部,false则不平分。<br/>默认值:false。<br/>**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。|
857| textBackgroundStyle<sup>18+</sup> | [TextBackgroundStyle](ts-basic-components-span.md#textbackgroundstyle11对象说明) | 否 | 是    | 文本背景样式。<br/>**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。|
858
859>  **说明:**
860>
861>  在RichEditorTextStyle中,fontWeight是设置字体粗细的输入参数。
862>  而在RichEditorTextStyleResult中,会将之前设置的字体粗细转换为数字后返回。
863>  转换关系如下:
864>
865>  | RichEditorTextStyle中的fontWeight | RichEditorTextStyleResult中的fontWeight |
866>  | ---- | ----------------------------------- |
867>  | 100   | 0 |
868>  | 200   | 1 |
869>  | 300   | 2 |
870>  | 400   | 3 |
871>  | 500   | 4 |
872>  | 600   | 5 |
873>  | 700   | 6 |
874>  | 800   | 7 |
875>  | 900   | 8 |
876>  | Lighter   | 12 |
877>  | Normal   | 10 |
878>  | Regular   | 14 |
879>  | Medium   | 13 |
880>  | Bold   | 9 |
881>  | Bolder   | 11 |
882>
883>  RichEditorSymbolSpanStyle和RichEditorSymbolSpanStyleResult中fontWeight的转换关系,
884>  与RichEditorTextStyle和RichEditorTextStyleResult中fontWeight的转换关系一致。
885
886## RichEditorSymbolSpanStyleResult<sup>11+</sup>
887
888后端返回的SymbolSpan样式信息。
889
890**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
891
892**系统能力:** SystemCapability.ArkUI.ArkUI.Full
893
894| 名称 | 类型  | 只读 | 可选 | 说明                               |
895| ------ | -------- | ---- | ------------------------------|-------- |
896| fontColor | Array\<[ResourceColor](ts-types.md#resourcecolor)\> | 否 | 否 | SymbolSpan组件颜色。<br/> 默认值:不同渲染策略下默认值不同。 |
897| fontSize | number \| string \| [Resource](ts-types.md#resource) | 否 | 否 | SymbolSpan组件大小,默认单位为fp。<br/>默认值:跟随主题。|
898| fontWeight | number \| [FontWeight](ts-appendix-enums.md#fontweight) \| string  | 否 | 否 | SymbolSpan组件粗细。<br/>number类型取值[100,900],取值间隔为100,默认为400,取值越大,字体越粗。<br/>string类型仅支持number类型取值的字符串形式,例如“400”,以及“bold”、“bolder”、“lighter”、“regular” 、“medium”分别对应FontWeight中相应的枚举值。<br/>默认值:FontWeight.Normal。|
899| renderingStrategy | [SymbolRenderingStrategy](ts-basic-components-symbolGlyph.md#symbolrenderingstrategy11枚举说明)	| 否 | 否 | SymbolSpan组件渲染策略。<br/>默认值:SymbolRenderingStrategy.SINGLE。<br/>
900| effectStrategy | [SymbolEffectStrategy](ts-basic-components-symbolGlyph.md#symboleffectstrategy11枚举说明)	| 否 | 否 | SymbolSpan组件动效策略。<br/>默认值:SymbolEffectStrategy.NONE。<br/>
901
902## RichEditorImageSpanResult
903
904后端返回的图片信息。
905
906**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
907
908**系统能力:** SystemCapability.ArkUI.ArkUI.Full
909
910| 名称               | 类型                                                                   | 只读 | 可选  | 说明               |
911|------------------|-------------------------------------------------------------------|-----|-------|-----------|
912| spanPosition     | [RichEditorSpanPosition](#richeditorspanposition)                 | 否 | 否   | Span位置。|
913| valuePixelMap    | [PixelMap](../../apis-image-kit/arkts-apis-image-PixelMap.md)                    | 否 | 是   | 图片内容。|
914| valueResourceStr | [ResourceStr](ts-types.md#resourcestr)                            | 否 | 是   | 图片资源id。|
915| imageStyle       | [RichEditorImageSpanStyleResult](#richeditorimagespanstyleresult) | 否 | 否 | 图片样式。|
916| offsetInSpan     | [number, number] | 否 | 否 | Span里图片的起始和结束位置。|
917
918## RichEditorImageSpanStyleResult
919
920后端返回的图片样式信息。
921
922**系统能力:** SystemCapability.ArkUI.ArkUI.Full
923
924| 名称            | 类型                                          | 只读 | 可选   | 说明        |
925| ------------- | ---------------------------------------- | ---- | -----|---- |
926| size          | [number, number]                         | 否 | 否    | 图片的宽度和高度,单位为px。默认值:size的默认值与objectFit的值有关,不同的objectFit值对应的size默认值也不同。objectFit的值为Cover时,图片高度为组件高度减去组件上下内边距,图片宽度为组件宽度减去组件左右内边距。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
927| verticalAlign | [ImageSpanAlignment](ts-appendix-enums.md#imagespanalignment10) | 否 | 否    | 图片垂直对齐方式。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
928| objectFit     | [ImageFit](ts-appendix-enums.md#imagefit) | 否 | 否    | 图片缩放类型。   <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
929| layoutStyle<sup>12+</sup> | [RichEditorLayoutStyle](#richeditorlayoutstyle11)     | 否 | 是   | 图片布局风格。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 |
930
931## RichEditorLayoutStyle<sup>11+</sup>
932
933图片布局信息。
934
935**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
936
937**系统能力:** SystemCapability.ArkUI.ArkUI.Full
938
939|名称	|类型	 | 只读 | 可选|	说明|
940| -------------  | -----------------------            | ---- | ----------|-------------------------------------------------- |
941|margin	         |  [Dimension](ts-types.md#dimension10) \| [Margin](ts-types.md#margin)	                       |  否|  是  |	外边距类型,用于描述组件不同方向的外边距。<br/>参数为Dimension类型时,四个方向外边距同时生效。|
942|borderRadius	   |  [Dimension](ts-types.md#dimension10) \| [BorderRadiuses](ts-types.md#borderradiuses9) |  否 |  是  |	圆角类型,用于描述组件边框圆角半径。<br/>参数为Dimension类型时,不支持以Percentage形式设置。|
943
944## RichEditorOptions
945
946RichEditor初始化参数。
947
948**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
949
950**系统能力:** SystemCapability.ArkUI.ArkUI.Full
951
952| 名称         | 类型                                        | 只读 | 可选  | 说明      |
953| ---------- | ---------------------------------------- | ---- | ----|--- |
954| controller | [RichEditorController](#richeditorcontroller) | 否 | 否    | 富文本控制器。 |
955
956## RichEditorStyledStringOptions<sup>12+</sup>
957
958RichEditor初始化参数。
959
960**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
961
962**系统能力:** SystemCapability.ArkUI.ArkUI.Full
963
964| 名称         | 类型                                       | 只读 | 可选   | 说明      |
965| ---------- | ---------------------------------------- | ---- | ----|--- |
966| controller | [RichEditorStyledStringController](#richeditorstyledstringcontroller12) | 否 | 否    | 富文本控制器。 |
967
968## RichEditorChangeValue<sup>12+</sup>
969
970图文变化信息。
971
972**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
973
974**系统能力:** SystemCapability.ArkUI.ArkUI.Full
975
976| 名称                    | 类型                                        | 只读 | 可选   | 说明                  |
977| --------------------- | ---------------------------------------- | ---- | -------|------------ |
978| rangeBefore | [TextRange](ts-text-common.md#textrange12) | 否 | 否    | 即将被替换内容的开始和结束索引。 |
979| replacedSpans | Array<[RichEditorTextSpanResult](#richeditortextspanresult)> | 否 | 否    | 替换后文本Span的具体信息。 |
980| replacedImageSpans | Array<[RichEditorImageSpanResult](#richeditorimagespanresult)> | 否 | 否    | 替换后ImageSpan的具体信息。 |
981| replacedSymbolSpans | Array<[RichEditorTextSpanResult](#richeditortextspanresult)> | 否 | 否    | 替换后SymbolSpan的具体信息。 |
982
983## RichEditorBaseController<sup>12+</sup>
984
985RichEditor组件控制器基类。
986
987### getCaretOffset<sup>10+</sup>
988
989getCaretOffset(): number
990
991返回当前光标所在位置。
992
993**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
994
995**系统能力:** SystemCapability.ArkUI.ArkUI.Full
996
997**返回值:**
998
999| 类型     | 说明        |
1000| ------ | --------- |
1001| number | 当前光标所在位置。 |
1002
1003### setCaretOffset<sup>10+</sup>
1004
1005setCaretOffset(offset: number): boolean
1006
1007设置光标位置。
1008
1009**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1010
1011**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1012
1013**参数:**
1014
1015| 参数名    | 类型   | 必填   | 说明                |
1016| ------ | ------ | ---- | -------------------- |
1017| offset | number | 是    | 光标偏移位置。超出所有内容范围时,设置失败。 |
1018
1019**返回值:**
1020
1021| 类型      | 说明        |
1022| ------- | --------- |
1023| boolean | 光标是否设置成功。<br/>true表示光标位置设置成功,false表示未成功。 |
1024
1025### closeSelectionMenu<sup>10+</sup>
1026
1027closeSelectionMenu(): void
1028
1029关闭自定义选择菜单或系统默认选择菜单。
1030
1031**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1032
1033**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1034
1035### getTypingStyle<sup>11+</sup>
1036
1037getTypingStyle(): RichEditorTextStyle
1038
1039获取用户预设的文本样式。
1040
1041**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1042
1043**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1044
1045**返回值:**
1046
1047| 类型                                       | 说明      |
1048| ---------------------------------------- | ------- |
1049| [RichEditorTextStyle](#richeditortextstyle) | 用户预设样式。 |
1050
1051### setTypingStyle<sup>11+</sup>
1052
1053setTypingStyle(value: RichEditorTextStyle): void
1054
1055设置用户预设的文本样式。
1056
1057**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1058
1059**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1060
1061**参数:**
1062
1063| 参数名   | 类型                                     | 必填   | 说明  |
1064| ----- | ---------------------------------------- | ---- | ----- |
1065| value | [RichEditorTextStyle](#richeditortextstyle) | 是    | 预设样式。 |
1066
1067### setTypingParagraphStyle<sup>20+</sup>
1068
1069setTypingParagraphStyle(style: RichEditorParagraphStyle): void
1070
1071设置用户预设的段落样式。仅在组件内容为空或组件末尾换行后,输入文本生效。
1072
1073**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。
1074
1075**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1076
1077**参数:**
1078
1079| 参数名   | 类型                                     | 必填   | 说明  |
1080| ----- | ---------------------------------------- | ---- | ----- |
1081| style | [RichEditorParagraphStyle](#richeditorparagraphstyle11) | 是    | 预设段落样式。 |
1082
1083### setSelection<sup>11+</sup>
1084
1085setSelection(selectionStart:&nbsp;number, selectionEnd:&nbsp;number, options?:&nbsp;SelectionOptions): void
1086
1087支持设置组件内的内容选中,选中部分背板高亮。
1088
1089selectionStart和selectionEnd均为-1时表示全选,均为0时可以清空选中区。
1090
1091未获焦时调用该接口不产生选中效果。
1092
1093从API version 12开始,在2in1设备中,无论options取何值,调用setSelection接口都不会弹出菜单,此外,如果组件中已经存在菜单,调用setSelection接口会关闭菜单。
1094
1095在非2in1设备中,options取值为MenuPolicy.DEFAULT时,遵循以下规则:
1096
10971. 组件内有手柄菜单时,接口调用后不关闭菜单,并且调整菜单位置。
1098
10992. 组件内有不带手柄的菜单时,接口调用后不关闭菜单,并且菜单位置不变。
1100
11013. 组件内无菜单时,接口调用后也无菜单显示。
1102
1103**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1104
1105**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1106
1107**参数:**
1108
1109| 参数名            | 类型   | 必填   | 说明    |
1110| -------------- | ------ | ---- | ------- |
1111| selectionStart | number | 是    | 选中开始位置。 |
1112| selectionEnd   | number | 是    | 选中结束位置。 |
1113| options<sup>12+</sup>   | [SelectionOptions](ts-universal-attributes-text-style.md#selectionoptions12对象说明) | 否    | 选择项配置。 |
1114
1115### isEditing<sup>12+</sup>
1116
1117isEditing(): boolean
1118
1119获取当前富文本的编辑状态。
1120
1121**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1122
1123**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1124
1125**返回值:**
1126
1127| 类型    | 说明                          |
1128| ------- | ----------------------------- |
1129| boolean | true为编辑态,false为非编辑态。 |
1130
1131### stopEditing<sup>12+</sup>
1132
1133stopEditing(): void
1134
1135退出编辑态。
1136
1137**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1138
1139**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1140
1141### getLayoutManager<sup>12+</sup>
1142
1143getLayoutManager(): LayoutManager
1144
1145获取布局管理器对象。
1146
1147**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1148
1149**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1150
1151**返回值:**
1152
1153| 类型                                       | 说明      |
1154| ---------------------------------------- | ------- |
1155| [LayoutManager](ts-text-common.md#layoutmanager12) | 布局管理器对象。 |
1156
1157### getPreviewText<sup>12+</sup>
1158
1159getPreviewText(): PreviewText
1160
1161获取预上屏信息。
1162
1163**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1164
1165**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1166
1167**返回值:**
1168
1169| 类型                                       | 说明      |
1170| ---------------------------------------- | ------- |
1171| [PreviewText](ts-text-common.md#previewtext12) | 预上屏信息。 |
1172
1173### getCaretRect<sup>18+</sup>
1174
1175getCaretRect(): RectResult | undefined
1176
1177返回当前光标与RichEditor组件的相对位置。如果光标不闪烁,返回undefined。
1178
1179**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
1180
1181**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1182
1183**返回值:**
1184
1185| 类型     | 说明        |
1186| ------ | --------- |
1187| [RectResult](ts-universal-attributes-on-child-touch-test.md#rectresult) \| undefined | 当前光标与RichEditor的相对位置。 |
1188
1189## RichEditorController
1190
1191RichEditor组件的控制器,继承自[RichEditorBaseController](#richeditorbasecontroller12)。
1192
1193### 导入对象
1194
1195```
1196controller: RichEditorController = new RichEditorController();
1197```
1198
1199### addTextSpan
1200
1201addTextSpan(content: ResourceStr, options?: RichEditorTextSpanOptions): number
1202
1203添加文本内容,如果组件光标闪烁,插入后光标位置更新为新插入文本的后面。
1204
1205**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1206
1207**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1208
1209**参数:**
1210
1211| 参数名     | 类型                                     | 必填   | 说明  |
1212| ------- | ---------------------------------------- | ---- | ----- |
1213| content   | [ResourceStr](ts-types.md#resourcestr)   | 是    | 文本内容。 <br>从API version 20开始,支持Resource类型。|
1214| options | [RichEditorTextSpanOptions](#richeditortextspanoptions) | 否    | 文本选项。 |
1215
1216**返回值:**
1217
1218| 类型     | 说明                   |
1219| ------ | -------------------- |
1220| number | 添加完成的TextSpan在所有Span中的索引位置。 |
1221
1222### addImageSpan
1223
1224addImageSpan(value: PixelMap | ResourceStr, options?: RichEditorImageSpanOptions): number
1225
1226添加图片内容,如果组件光标闪烁,插入后光标位置更新为新插入图片的后面。
1227
1228不建议直接添加网络图片。
1229
1230**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1231
1232**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1233
1234**参数:**
1235
1236| 参数名     | 类型                                     | 必填   | 说明  |
1237| ------- | ---------------------------------------- | ---- | ----- |
1238| value   | [PixelMap](../../apis-image-kit/arkts-apis-image-PixelMap.md) \| [ResourceStr](ts-types.md#resourcestr) | 是    | 图片内容。 |
1239| options | [RichEditorImageSpanOptions](#richeditorimagespanoptions) | 否    | 图片选项。 |
1240
1241**返回值:**
1242
1243| 类型     | 说明                   |
1244| ------ | -------------------- |
1245| number | 添加完成的ImageSpan在所有Span中的索引位置。 |
1246
1247### addBuilderSpan<sup>11+</sup>
1248
1249addBuilderSpan(value: CustomBuilder, options?: RichEditorBuilderSpanOptions): number
1250
1251在RichEditor中添加用户自定义布局(BuilderSpan)。
1252
1253> **说明:**
1254>
1255> - RichEditor组件添加占位Span,占位Span调用系统的measure方法计算真实的长宽和位置。
1256> - 可通过[RichEditorBuilderSpanOptions](#richeditorbuilderspanoptions11)设置此builder在RichEditor中的index(一个文字为一个单位)。
1257> - 此占位Span不可获焦,支持拖拽,支持部分通用属性,占位、删除等能力等同于ImageSpan,长度视为一个文字。
1258> - 支持通过[bindSelectionMenu](#bindselectionmenu)设置自定义菜单。
1259> - 不支持通过[getSpans](#getspans),[getSelection](#getselection11),[onSelect](#onselect),[aboutToDelete](#abouttodelete)获取builderSpan信息。
1260> - 不支持通过[updateSpanStyle](#updatespanstyle),[updateParagraphStyle](#updateparagraphstyle11)等方式更新builder。
1261> - 对此builder节点进行复制或粘贴不生效。
1262> - builder的布局约束由RichEditor传入,如果builder里最外层组件不设置大小,则会用RichEditor的大小作为maxSize。
1263> - builder的手势相关事件机制与通用手势事件相同,如果builder中未设置透传,则仅有builder中的子组件响应。
1264> - 如果组件光标闪烁,插入后光标位置更新为新插入builder的后面。
1265
1266通用属性仅支持[size](ts-universal-attributes-size.md#size)、[padding](ts-universal-attributes-size.md#padding)、[margin](ts-universal-attributes-size.md#margin)、[aspectRatio](ts-universal-attributes-layout-constraints.md#aspectratio)、[borderStyle](ts-universal-attributes-border.md#borderstyle)、[borderWidth](ts-universal-attributes-border.md#borderwidth)、[borderColor](ts-universal-attributes-border.md#bordercolor)、[borderRadius](ts-universal-attributes-border.md#borderradius)、[backgroundColor](ts-universal-attributes-background.md#backgroundcolor)、[backgroundBlurStyle](ts-universal-attributes-background.md#backgroundblurstyle9)、[opacity](ts-universal-attributes-opacity.md)、[blur](ts-universal-attributes-image-effect.md#blur)、[backdropBlur](ts-universal-attributes-background.md#backdropblur)、[shadow](ts-universal-attributes-image-effect.md#shadow)、[grayscale](ts-universal-attributes-image-effect.md#grayscale)、[brightness](ts-universal-attributes-image-effect.md#brightness)、[saturate](ts-universal-attributes-image-effect.md#saturate)、[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)。
1267
1268**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1269
1270**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1271
1272**参数:**
1273
1274| 参数名     | 类型                                     | 必填   | 说明       |
1275| ------- | ---------------------------------------- | ---- | ---------- |
1276| value   | [CustomBuilder](ts-types.md#custombuilder8) | 是    | 自定义组件。     |
1277| options | [RichEditorBuilderSpanOptions](#richeditorbuilderspanoptions11) | 否    | builder选项。 |
1278
1279**返回值:**
1280
1281| 类型     | 说明                     |
1282| ------ | ---------------------- |
1283| number | 添加完成的builderSpan在所有Span中的索引位置。 |
1284
1285### addSymbolSpan<sup>11+</sup>
1286
1287addSymbolSpan(value: Resource, options?: RichEditorSymbolSpanOptions ): number
1288
1289在RichEditor中添加图标小符号(SymbolSpan),如果组件光标闪烁,插入后光标位置更新为新插入SymbolSpan的后面。
1290
1291暂不支持手势、复制、拖拽处理。
1292
1293**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1294
1295**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1296
1297**参数:**
1298
1299| 参数名     | 类型                                     | 必填   | 说明  |
1300| ------- | ---------------------------------------- | ---- | ----- |
1301| value   | [Resource](ts-types.md#resource)         | 是    | symbol资源信息。 |
1302| options | [RichEditorSymbolSpanOptions](#richeditorsymbolspanoptions11) | 否    | symbol选项。 |
1303
1304**返回值:**
1305
1306| 类型     | 说明                    |
1307| ------ | --------------------- |
1308| number | 添加完成的SymbolSpan在所有Span中的索引位置。 |
1309
1310### updateSpanStyle
1311
1312updateSpanStyle(value: RichEditorUpdateTextSpanStyleOptions | RichEditorUpdateImageSpanStyleOptions | RichEditorUpdateSymbolSpanStyleOptions): void
1313
1314更新文本、图片或SymbolSpan样式。<br/>若只更新了一个Span的部分内容,则会根据更新部分、未更新部分将该Span拆分为多个Span。
1315
1316使用该接口更新文本、图片或SymbolSpan样式时默认不会关闭自定义文本选择菜单。
1317
1318**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1319
1320**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1321
1322**参数:**
1323
1324| 参数名 | 类型 | 必填 | 说明                               |
1325| ------ | -------- | ---- | -------------------------------------- |
1326| value | [RichEditorUpdateTextSpanStyleOptions](#richeditorupdatetextspanstyleoptions) \| [RichEditorUpdateImageSpanStyleOptions](#richeditorupdateimagespanstyleoptions) \| [RichEditorUpdateSymbolSpanStyleOptions](#richeditorupdatesymbolspanstyleoptions11) | 是 | 文本、图片或SymbolSpan的样式选项信息。 |
1327
1328>  **说明:**
1329>
1330>  当start大于end时为异常情况,此时start为0,end为无穷大。
1331
1332### updateParagraphStyle<sup>11+</sup>
1333
1334updateParagraphStyle(value: RichEditorParagraphStyleOptions): void
1335
1336更新段落的样式。
1337
1338**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1339
1340**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1341
1342**参数:**
1343
1344| 参数名    | 类型                                       | 必填   | 说明         |
1345| ----- | ---------------------------------------- | ---- | ---------- |
1346| value | [RichEditorParagraphStyleOptions](#richeditorparagraphstyleoptions11) | 是    | 段落的样式选项信息。 |
1347
1348### getSpans
1349
1350getSpans(value?: RichEditorRange): Array<RichEditorImageSpanResult | RichEditorTextSpanResult>
1351
1352获取span信息。
1353
1354**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1355
1356**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1357
1358**参数:**
1359
1360| 参数名   | 类型                                | 必填   | 说明        |
1361| ----- | ----------------------------------- | ---- | ----------- |
1362| value | [RichEditorRange](#richeditorrange) | 否    | 需要获取span范围。 |
1363
1364**返回值:**
1365
1366| 类型                                       | 说明           |
1367| ---------------------------------------- | ------------ |
1368| Array<[RichEditorImageSpanResult](#richeditorimagespanresult) \| [RichEditorTextSpanResult](#richeditortextspanresult)> | 文本和图片Span信息。 |
1369
1370### deleteSpans
1371
1372deleteSpans(value?: RichEditorRange): void
1373
1374删除指定范围内的文本和图片。
1375
1376**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1377
1378**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1379
1380**参数:**
1381
1382| 参数名   | 类型                                | 必填   | 说明                |
1383| ----- | ----------------------------------- | ---- | ------------------- |
1384| value | [RichEditorRange](#richeditorrange) | 否    | 删除范围。省略时,删除所有文本和图片。 |
1385
1386### getParagraphs<sup>11+</sup>
1387
1388getParagraphs(value?: RichEditorRange): Array\<RichEditorParagraphResult>
1389
1390获取指定范围的段落信息。
1391
1392**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1393
1394**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1395
1396**参数:**
1397
1398| 参数名   | 类型                                | 必填   | 说明       |
1399| ----- | ----------------------------------- | ---- | ---------- |
1400| value | [RichEditorRange](#richeditorrange) | 否    | 需要获取段落的范围。 |
1401
1402**返回值:**
1403
1404| 类型                                       | 说明       |
1405| ---------------------------------------- | -------- |
1406| Array\<[RichEditorParagraphResult](#richeditorparagraphresult11)> | 选中段落的信息。 |
1407
1408### getSelection<sup>11+</sup>
1409
1410getSelection(): RichEditorSelection
1411
1412获取选中内容。未选中时,返回光标所在span信息。
1413
1414**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1415
1416**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1417
1418**返回值:**
1419
1420| 类型                                       | 说明      |
1421| ---------------------------------------- | ------- |
1422| [RichEditorSelection](#richeditorselection) | 选中内容信息。 |
1423
1424### fromStyledString<sup>12+</sup>
1425
1426fromStyledString(value: StyledString): Array\<RichEditorSpan>
1427
1428将属性字符串转换为span信息。
1429
1430**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1431
1432**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1433
1434**参数:**
1435
1436| 参数名   | 类型                                | 必填   | 说明       |
1437| ----- | ----------------------------------- | ---- | ---------- |
1438| value | [StyledString](ts-universal-styled-string.md#styledstring) | 是    | 转换前的属性字符串。 |
1439
1440**返回值:**
1441
1442| 类型                                       | 说明      |
1443| ---------------------------------------- | ------- |
1444| Array<[RichEditorSpan](#richeditorspan12)>  | 文本和图片Span信息。 |
1445
1446**错误码:**
1447
1448以下错误码的详细介绍请参考[通用错误码](../../errorcode-universal.md)。
1449
1450| 错误码ID | 错误信息                        |
1451| -------- | ------------------------------ |
1452| 401      | The parameter check failed.  |
1453
1454### toStyledString<sup>12+</sup>
1455
1456toStyledString(value: RichEditorRange): StyledString
1457
1458将给定范围的组件内容转换成属性字符串,SymbolSpan和BuilderSpan不支持转换。
1459
1460**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1461
1462**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1463
1464**参数:**
1465
1466| 参数名   | 类型                                | 必填   | 说明       |
1467| ----- | ----------------------------------- | ---- | ---------- |
1468| value | [RichEditorRange](#richeditorrange) | 是   | 需要获取的范围。 |
1469
1470**返回值:**
1471
1472| 类型                                       | 说明       |
1473| ---------------------------------------- | -------- |
1474| [StyledString](ts-universal-styled-string.md#styledstring) | 转换后的属性字符串 |
1475
1476**错误码:**
1477
1478以下错误码详细介绍请参考[通用错误码](../../errorcode-universal.md)。
1479
1480| 错误码ID | 错误信息                        |
1481| -------- | ------------------------------ |
1482| 401      | The parameter check failed.  |
1483
1484
1485## RichEditorStyledStringController<sup>12+</sup>
1486
1487使用属性字符串构建的RichEditor组件的控制器,继承自[RichEditorBaseController](#richeditorbasecontroller12)。
1488
1489### 导入对象
1490
1491```
1492controller: RichEditorStyledStringController = new RichEditorStyledStringController();
1493```
1494
1495### getSelection<sup>12+</sup>
1496
1497getSelection(): RichEditorRange
1498
1499获取富文本当前的选中区域范围。
1500
1501**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1502
1503**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1504
1505**返回值:**
1506
1507| 类型                                       | 说明      |
1508| ---------------------------------------- | ------- |
1509| [RichEditorRange](#richeditorrange) | 选中区域范围。 |
1510
1511### setStyledString<sup>12+</sup>
1512
1513setStyledString(styledString: StyledString): void
1514
1515设置富文本组件显示的属性字符串。
1516
1517**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1518
1519**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1520
1521**参数:**
1522
1523| 参数名   | 类型   | 必填   | 说明                |
1524| ----- | ------ | ---- | ------------------- |
1525| styledString | [StyledString](ts-universal-styled-string.md#styledstring) | 是    | 属性字符串。<br/>**说明:** <br/>StyledString的子类[MutableStyledString](ts-universal-styled-string.md#mutablestyledstring)也可以作为入参值。 |
1526
1527### getStyledString<sup>12+</sup>
1528
1529getStyledString(): MutableStyledString
1530
1531获取富文本组件显示的属性字符串。
1532
1533**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1534
1535**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1536
1537**返回值:**
1538
1539| 类型    | 说明                          |
1540| ------- | ----------------------------- |
1541| [MutableStyledString](ts-universal-styled-string.md#mutablestyledstring) | 富文本组件显示的属性字符串 |
1542
1543### onContentChanged<sup>12+</sup>
1544
1545onContentChanged(listener: StyledStringChangedListener): void
1546
1547注册文本内容变化回调,该回调会在后端程序导致文本内容变更时触发。
1548
1549**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1550
1551**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1552
1553**参数:**
1554
1555| 参数名   | 类型   | 必填   | 说明                |
1556| ----- | ------ | ---- | ------------------- |
1557| listener | [StyledStringChangedListener](ts-text-common.md#styledstringchangedlistener12) | 是    | 文本内容变化回调监听器。 |
1558
1559## RichEditorSelection
1560
1561选中内容信息。
1562
1563**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1564
1565**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1566
1567| 名称        | 类型                                        | 只读 | 可选   | 说明      |
1568| --------- | ---------------------------------------- | ---- | ---|---- |
1569| selection | [number, number]                        | 否 | 否    | 选中范围。   |
1570| spans     | Array<[RichEditorTextSpanResult](#richeditortextspanresult) \| [RichEditorImageSpanResult](#richeditorimagespanresult)> | 否 | 否    | span信息。 |
1571
1572## RichEditorRange
1573
1574定义RichEditor的范围。
1575
1576**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1577
1578**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1579
1580| 名称  | 类型      | 只读 | 可选 | 说明                                                         |
1581| ----- | ------ | ---- | ---------|--------------------------------------------------- |
1582| start | number | 否 | 是   | 需要更新样式的文本起始位置,省略或者设置负值时表示从0开始。  |
1583| end   | number | 否 | 是   | 需要更新样式的文本结束位置,省略或者超出文本范围时表示无穷大。 |
1584
1585
1586## RichEditorSpanStyleOptions
1587
1588文本样式选项。
1589
1590继承自[RichEditorRange](#richeditorrange)。
1591
1592**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1593
1594**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1595
1596## RichEditorUpdateTextSpanStyleOptions
1597
1598文本样式选项。
1599
1600继承自[RichEditorSpanStyleOptions](#richeditorspanstyleoptions)。
1601
1602**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1603
1604| 名称      | 类型                                         | 只读 | 可选| 说明       |
1605| --------- | ------------------------------------------- | ---- | -----|----- |
1606| textStyle | [RichEditorTextStyle](#richeditortextstyle) | 否 | 否   | 文本样式。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1607| urlStyle<sup>19+</sup>  | [RichEditorUrlStyle](#richeditorurlstyle19)   | 否 | 是   | url信息。<br/>默认值:undefined <br/>**原子化服务API:** 从API version 19开始,该接口支持在原子化服务中使用。|
1608
1609## RichEditorUpdateImageSpanStyleOptions
1610
1611图片的样式选项。
1612
1613继承自[RichEditorSpanStyleOptions](#richeditorspanstyleoptions)。
1614
1615**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1616
1617**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1618
1619| 名称         | 类型                                        | 只读 | 可选   | 说明                              |
1620| ---------- | ---------------------------------------- | ---- | ----------|--------------------- |
1621| imageStyle | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | 否| 否    | 图片样式。                           |
1622
1623## RichEditorUpdateSymbolSpanStyleOptions<sup>11+</sup>
1624
1625SymbolSpan样式选项。
1626
1627继承自[RichEditorSpanStyleOptions](#richeditorspanstyleoptions)。
1628
1629**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1630
1631**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1632
1633| 名称        | 类型                                                       | 只读 | 可选 | 说明       |
1634| ----------- | --------------------------------------------------------- | ---- | ----|------ |
1635| symbolStyle | [RichEditorSymbolSpanStyle](#richeditorsymbolspanstyle11) | 否 | 否   | 组件样式。 |
1636
1637## RichEditorParagraphStyleOptions<sup>11+</sup>
1638
1639段落样式选项。
1640
1641继承自[RichEditorRange](#richeditorrange)。
1642
1643**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1644
1645**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1646
1647| 名称    | 类型                                       | 只读 | 可选   | 说明                                 |
1648| ----- | ---------------------------------------- | ---- | ------------|---------------------- |
1649| style | [RichEditorParagraphStyle](#richeditorparagraphstyle11) | 否 | 否    | 段落样式。                              |
1650
1651>  **说明:**
1652>
1653>  接口作用的范围:设定的区间所涉及的段落。
1654
1655
1656## RichEditorParagraphStyle<sup>11+</sup>
1657
1658段落样式。
1659
1660**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1661
1662| 名称            | 类型                                       | 只读 | 可选   | 说明                 |
1663| ------------- | ---------------------------------------- | ---- | --------|---------- |
1664| textAlign     | [TextAlign](ts-appendix-enums.md#textalign) | 否    | 是 | 设置文本段落在水平方向的对齐方式。默认值:TextAlign.START  <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
1665| leadingMargin | [Dimension](ts-types.md#dimension10) \| [LeadingMarginPlaceholder](#leadingmarginplaceholder11) | 否    | 是 | 设置文本段落缩进,当段落仅存在ImageSpan或BuilderSpan时,此属性值不生效。参数为Dimension类型时,不支持以Percentage形式设置。默认值:{"size":["0.00px","0.00px"]} <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
1666| wordBreak<sup>12+</sup> |  [WordBreak](ts-appendix-enums.md#wordbreak11) | 否    | 是 | 设置断行规则。 <br />默认值:WordBreak.BREAK_WORD <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
1667| lineBreakStrategy<sup>12+</sup> | [LineBreakStrategy](ts-appendix-enums.md#linebreakstrategy12) | 否 | 是 | 设置折行规则。 <br />默认值:LineBreakStrategy.GREEDY<br />在wordBreak不等于breakAll的时候生效,不支持连字符。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
1668| paragraphSpacing<sup>19+</sup> | number | 否    | 是 | 设置段落间距大小。<br/>单位:fp<br/>段落间距默认大小为0。<br/>**原子化服务API:** 从API version 19开始,该接口支持在原子化服务中使用。|
1669| textVerticalAlign<sup>20+</sup> | [TextVerticalAlign](ts-text-common.md#textverticalalign20) |  否  | 是 | 设置文本段落在垂直方向的对齐方式。<br/>默认值:TextVerticalAlign.BASELINE <br/>**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。|
1670
1671## LeadingMarginPlaceholder<sup>11+</sup>
1672
1673前导边距占位符,用于表示文本段落左侧与组件边缘之间的距离。
1674
1675**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1676
1677| 名称       | 类型                                      | 只读 | 可选   | 说明             |
1678| -------- | ---------------------------------------- | ---- | ---------|----- |
1679| pixelMap | [PixelMap](../../apis-image-kit/arkts-apis-image-PixelMap.md)  | 否 | 否    | 图片内容。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
1680| size     | \[[Dimension](ts-types.md#dimension10), [Dimension](ts-types.md#dimension10)\]  | 否 | 否    | 图片大小,不支持设置百分比。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 |
1681
1682## RichEditorParagraphResult<sup>11+</sup>
1683
1684后端返回的段落信息。
1685
1686**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1687
1688**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1689
1690| 名称    | 类型                                        | 只读 | 可选   | 说明      |
1691| ----- | ---------------------------------------- | ---- | ---|---- |
1692| style | [RichEditorParagraphStyle](#richeditorparagraphstyle11) |否| 否    | 段落样式。   |
1693| range | \[number, number\]                      |否 | 否    | 段落起始和结束位置。 |
1694
1695## RichEditorTextSpanOptions
1696
1697添加文本的偏移位置和文本样式信息。
1698
1699**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1700
1701| 名称                           | 类型                                         | 只读 | 可选  | 说明                         |
1702| ---------------------------- | ---------------------------------------- | ---- | ------|-------------------- |
1703| offset                       | number                                   | 否 | 是    | 添加文本的位置。省略时,添加到所有内容的最后。<br/>当值小于0时,放在所有内容最前面;当值大于所有内容长度时,放在所有内容最后面。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1704| style                        | [RichEditorTextStyle](#richeditortextstyle) | 否 | 是    | 文本样式信息。省略时,使用系统默认文本信息。     <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1705| paragraphStyle<sup>11+</sup> | [RichEditorParagraphStyle](#richeditorparagraphstyle11) | 否 | 是    | 段落样式。                     <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 |
1706| gesture<sup>11+</sup>        | [RichEditorGesture](#richeditorgesture11) | 否  | 是    | 行为触发回调。省略时,仅使用系统默认行为。      <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
1707| urlStyle<sup>19+</sup>  | [RichEditorUrlStyle](#richeditorurlstyle19)  | 否  | 是   | url信息。<br/>默认值:undefined <br/>**原子化服务API:** 从API version 19开始,该接口支持在原子化服务中使用。|
1708
1709## RichEditorTextStyle
1710
1711文本样式信息。
1712
1713**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1714
1715| 名称                       | 类型                                      |  只读  | 可选   | 说明                           |
1716| ------------------------ | ---------------------------------------- | ---- | ---------|------------------------------- |
1717| fontColor                | [ResourceColor](ts-types.md#resourcecolor) | 否 | 是    | 文本颜色。<br/> 默认值:$r('sys.color.font_primary')。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1718| fontSize                 | [Length](ts-types.md#length) \| number            | 否| 是    | 设置字体大小,Length为number类型时,使用fp单位。字体默认大小16。不支持设置百分比字符串。字体大小设置为0时,显示默认字体大小。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1719| fontStyle                | [FontStyle](ts-appendix-enums.md#fontstyle) | 否 | 是    | 字体样式。<br/>默认值:FontStyle.Normal。          <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1720| fontWeight               | number \| [FontWeight](ts-appendix-enums.md#fontweight) \| string | 否 | 是    | 字体粗细。<br/>number类型取值[100,900],取值间隔为100,默认为400,取值越大,字体越粗。<br/>string类型仅支持number类型取值的字符串形式,例如“400”,以及“bold”、“bolder”、“lighter”、“regular” 、“medium”分别对应FontWeight中相应的枚举值。<br/>默认值:FontWeight.Normal。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1721| fontFamily               | [ResourceStr](ts-types.md#resourcestr) | 否 | 是    | 设置字体列表。默认字体'HarmonyOS Sans',当前支持'HarmonyOS Sans'字体和[注册自定义字体](../js-apis-font.md)。 <br/>默认字体:'HarmonyOS Sans'。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1722| decoration               | [DecorationStyleInterface](ts-universal-styled-string.md#decorationstyleinterface) | 否 | 是    | 设置文本装饰线的样式、颜色和粗细。<br/>type默认值:TextDecorationType.None <br/>color默认值:跟随字体颜色。<br/>style默认值:TextDecorationStyle.SOLID <br/>thicknessScale默认值:1.0 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1723| textShadow<sup>11+</sup> | [ShadowOptions](ts-universal-attributes-image-effect.md#shadowoptions对象说明)&nbsp;\|&nbsp;Array&lt;[ShadowOptions](ts-universal-attributes-image-effect.md#shadowoptions对象说明)> | 否 | 是    | 设置文字阴影效果。该接口支持以数组形式入参,实现多重文字阴影。<br/>**说明:**<br/>仅支持设置阴影模糊半径、颜色和偏移量,不支持智能取色。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
1724| lineHeight<sup>12+</sup>    | number \| string \| [Resource](ts-types.md#resource) | 否 | 是     |设置文本的文本行高,设置值不大于0时,不限制文本行高,自适应字体大小。number类型时单位为fp,不支持设置百分比字符串。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
1725| letterSpacing<sup>12+</sup> | number \| string             | 否 | 是     | 设置文本字符间距,当取值为负值时,文字会发生压缩,负值过小时会将组件内容区大小压缩为0,导致无内容显示,number类型时单位为fp,不支持设置百分比字符串。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
1726| fontFeature<sup>12+</sup> | string | 否 | 是 | 设置文字特性效果,比如数字等宽的特性。如果未设置,默认为变宽数字。设置无效字符保持默认。<br/>格式为:normal \| \<feature-tag-value\><br/>\<feature-tag-value\>的格式为:\<string\> \[ \<integer\> \| on \| off ]<br/>\<feature-tag-value\>的个数可以有多个,中间用','隔开。<br/>例如,使用等宽时钟数字的输入格式为:"ss01" on。<br/>Font Feature当前支持的属性见 [fontFeature属性列表](ts-basic-components-text.md#fontfeature12)。<br/>设置 Font Feature 属性,Font Feature 是 OpenType 字体的高级排版能力,如支持连字、数字等宽等特性,一般用在自定义字体中,其能力需要字体本身支持。<br/>更多 Font Feature 能力介绍可参考 https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prophttps://sparanoid.com/lab/opentype-features/<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
1727| halfLeading<sup>18+</sup> | boolean |否 | 是    | 文本是否将行间距平分至行的顶部与底部。<br/>true表示将行间距平分至行的顶部与底部,false则不平分。<br/>默认值:false。<br/>**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。|
1728| textBackgroundStyle<sup>18+</sup> | [TextBackgroundStyle](ts-basic-components-span.md#textbackgroundstyle11对象说明) | 否 | 是    | 文本背景样式。<br />默认值:<br />{<br />  color: Color.Transparent,<br />  radius: 0<br />} <br/>**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。|
1729
1730## PlaceholderStyle<sup>12+</sup>
1731
1732设置提示文本的字体样式。
1733
1734**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1735
1736**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1737
1738| 名称                           | 类型                                       | 只读 | 可选   | 说明                         |
1739| ---------------------------- | ---------------------------------------- | ---- | ----------|---------------- |
1740| font                         | [Font](ts-types.md#font)                    | 否 | 是    | 设置placeholder文本样式。<br/>默认值遵循主题设置。|
1741| fontColor                    | [ResourceColor](ts-types.md#resourcecolor)  | 否 | 是    | 设置placeholder文本颜色。<br/>默认值遵循主题设置。|
1742
1743## RichEditorImageSpanOptions
1744
1745设置图片的偏移位置和图片样式信息。
1746
1747**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1748
1749| 名称                    | 类型                                        | 只读 | 可选   | 说明                         |
1750| --------------------- | ---------------------------------------- | ---- | --------|------------------ |
1751| offset                | number                                   | 否 | 是    | 添加图片的位置。省略时,添加到所有内容的末尾。<br/>当值小于0时,设置在所有内容最前面;当值大于所有内容长度时,设置在所有内容最后面。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1752| imageStyle            | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | 否 | 是    | 图片样式信息。省略时,使用系统默认图片信息。     <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1753| gesture<sup>11+</sup> | [RichEditorGesture](#richeditorgesture11) | 否 | 是    | 行为触发回调。省略时,仅使用系统默认行为。      <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。|
1754| onHover<sup>14+</sup> | [OnHoverCallback](#onhovercallback14) | 否 | 是    | 鼠标悬停触发回调。省略时,不执行相关行为。     <br/>**原子化服务API:** 从API version 14开始,该接口支持在原子化服务中使用。|
1755
1756## RichEditorImageSpanStyle
1757
1758图片样式。
1759
1760**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1761
1762| 名称                        | 类型                                      | 只读 | 可选   | 说明                                       |
1763| ------------------------- | ---------------------------------------- | ---- | -------|-------------------------------- |
1764| size                      | [[Dimension](ts-types.md#dimension10), [Dimension](ts-types.md#dimension10)] | 否| 是    | 图片宽度和高度。默认值:与objectFit的值相关,不同的objectFit值有不同的默认尺寸。objectFit的值为Cover时,图片高度为组件高度减去组件上下内边距,宽度为组件宽度减去组件左右内边距。不支持以Percentage形式设置。  <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。                               |
1765| verticalAlign             | [ImageSpanAlignment](ts-appendix-enums.md#imagespanalignment10)| 否| 是    | 图片垂直对齐方式。<br/>默认值:ImageSpanAlignment.BOTTOM <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。|
1766| objectFit                 | [ImageFit](ts-appendix-enums.md#imagefit) | 否| 是    | 图片缩放类型。<br/> 默认值:ImageFit.Cover。  <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。       |
1767| layoutStyle<sup>11+</sup> | [RichEditorLayoutStyle](#richeditorlayoutstyle11) | 否| 是    | 图片布局风格。默认值:{"borderRadius":"","margin":""}<br/>   <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。                          |
1768
1769## RichEditorSymbolSpanOptions<sup>11+</sup>
1770
1771设置SymbolSpan组件的偏移位置和样式。
1772
1773**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1774
1775**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1776
1777| 名称     | 类型                                       | 只读 | 可选   | 说明                         |
1778| ------ | ---------------------------------------- | ---- | ----------------|---------- |
1779| offset | number                                   | 否 | 是    | 添加组件的位置。省略时,添加到所有内容的最后。<br/>如果值小于0,添加到所有内容的最前面;如果值大于所有内容的长度,添加到所有内容的最后面。 |
1780| style  | [RichEditorSymbolSpanStyle](#richeditorsymbolspanstyle11)  | 否 | 是    | 组件样式信息。省略时,使用系统默认样式信息。     |
1781
1782## RichEditorSymbolSpanStyle<sup>11+</sup>
1783
1784组件SymbolSpan样式信息。
1785
1786**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1787
1788**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1789
1790| 名称 | 类型  | 只读 | 可选 | 说明                               |
1791| ------ | -------- | ---- | --------------------|------------------ |
1792| fontColor | Array\<[ResourceColor](ts-types.md#resourcecolor)\> | 否| 是 | 设置SymbolSpan组件颜色。<br/> 默认值:不同渲染策略下默认值不同。 |
1793| fontSize | number \| string \| [Resource](ts-types.md#resource) | 否| 是 | 设置SymbolSpan组件大小,默认单位为fp。<br/>默认值:跟随主题。 |
1794| fontWeight | number \| [FontWeight](ts-appendix-enums.md#fontweight) \| string | 否| 是 | 设置SymbolSpan组件粗细。<br/>number类型取值[100,900],取值间隔为100,默认为400,取值越大,字体越粗。<br/>string类型仅支持number类型取值的字符串形式,例如“400”,以及“bold”、“bolder”、“lighter”、“regular” 、“medium”分别对应FontWeight中相应的枚举值。<br/>默认值:FontWeight.Normal。 |
1795| renderingStrategy | [SymbolRenderingStrategy](ts-basic-components-symbolGlyph.md#symbolrenderingstrategy11枚举说明)	| 否| 是 | 设置SymbolSpan组件渲染策略。<br/>默认值:SymbolRenderingStrategy.SINGLE。 |
1796| effectStrategy | [SymbolEffectStrategy](ts-basic-components-symbolGlyph.md#symboleffectstrategy11枚举说明)	| 否| 是 | 设置SymbolSpan组件动效策略。<br/>默认值:SymbolEffectStrategy.NONE。 |
1797
1798## RichEditorBuilderSpanOptions<sup>11+</sup>
1799
1800设置builder的偏移位置和样式。
1801
1802**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1803
1804**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1805
1806| 名称     | 类型      | 只读 | 可选   | 说明                                    |
1807| ------ | ------ | ---- | ----------|--------------------------- |
1808| offset | number | 否 | 是    | 添加builder的位置。省略或者为异常值时,添加到所有内容的最后。 |
1809
1810## RichEditorSpan<sup>12+</sup>
1811
1812type RichEditorSpan = RichEditorImageSpanResult | RichEditorTextSpanResult
1813
1814RichEditor span信息。
1815
1816**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1817
1818**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1819
1820| 类型   | 说明       |
1821| ------ | ---------- |
1822| [RichEditorImageSpanResult](#richeditorimagespanresult) | 后端返回的图片信息。 |
1823| [RichEditorTextSpanResult](#richeditortextspanresult) | 后端返回的文本信息。 |
1824
1825## SelectionMenuOptions
1826
1827菜单的选项。
1828
1829**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1830
1831| 名称          | 类型          | 只读 | 可选   | 说明            |
1832| ----------- | ---------- | ---- | -------|------ |
1833| onAppear    | [MenuOnAppearCallback](#menuonappearcallback12) | 否 | 是    | 自定义选择菜单弹出时回调。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
1834| onDisappear | Callback\<void\>  | 否 | 是    | 自定义选择菜单关闭时回调。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
1835| menuType<sup>13+</sup> | [MenuType](ts-text-common.md#menutype13枚举说明) | 否 | 是 | 自定义选择菜单类型。<br/>**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。<br/>默认值:MenuType.SELECTION_MENU。 |
1836| onMenuShow<sup>15+</sup> | [MenuCallback](#menucallback15) | 否 | 是 |  自定义选择菜单显示时回调。<br/>**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。 |
1837| onMenuHide<sup>15+</sup> | [MenuCallback](#menucallback15) | 否 | 是 |  自定义选择菜单隐藏时回调。<br/>**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。 |
1838| previewMenuOptions<sup>18+</sup> | [PreviewMenuOptions](#previewmenuoptions18) | 否 | 是 |  预览菜单的选项。 <br/>**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。 |
1839
1840## PreviewMenuOptions<sup>18+</sup>
1841
1842预览菜单的选项。
1843
1844**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
1845
1846**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1847
1848| 名称          | 类型          | 只读 | 可选   | 说明            |
1849| ----------- | ---------- | ---- | ----|--------- |
1850| hapticFeedbackMode | [HapticFeedbackMode](ts-universal-attributes-menu.md#hapticfeedbackmode18)| 否 | 是 | 菜单弹出时振动效果,当ImageSpan或BuilderSpan绑定预览菜单时生效。<br/>默认值:HapticFeedbackMode.DISABLED,菜单弹出时不振动。<br/>**说明:** 仅当应用具备ohos.permission.VIBRATE权限,且用户启用了触感反馈时才会生效。|
1851
1852## PasteEvent<sup>11+</sup>
1853
1854定义用户粘贴事件。
1855
1856**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
1857
1858**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1859
1860| 名称            |类型   | 只读 | 可选   | 说明                            |
1861| -------------- | ----------- | ---- | -----|------------------------ |
1862| preventDefault | Callback\<void\> | 否  | 是  | 阻止系统默认粘贴事件。 |
1863
1864## CutEvent<sup>12+</sup>
1865
1866定义用户剪切事件。
1867
1868**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1869
1870**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1871
1872| 名称             | 类型          | 只读 | 可选   | 说明                            |
1873| -------------- | ----------- | ---- | -------|---------------------- |
1874| preventDefault | Callback\<void\>  | 否 | 是    | 阻止系统默认剪切事件。 |
1875
1876## CopyEvent<sup>12+</sup>
1877
1878定义用户复制事件。
1879
1880**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1881
1882**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1883
1884| 名称             | 类型           | 只读 | 可选   | 说明                            |
1885| -------------- | ----------- | ---- | ---------|-------------------- |
1886| preventDefault | Callback\<void\>  | 否 | 是    | 阻止组件的默认复制操作。 |
1887
1888## RichEditorGesture<sup>11+</sup>
1889
1890用户手势事件。
1891
1892**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1893
1894**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1895
1896| 名称          | 类型            | 只读 | 可选   | 说明            |
1897| ----------- | ---------- | ---- | ------|------- |
1898| onClick    | Callback\<[ClickEvent](ts-universal-events-click.md#clickevent对象说明)\> | 否 | 是    | [ClickEvent](ts-universal-events-click.md#clickevent对象说明)为用户点击事件。<br/>点击完成时回调事件。<br/>双击时,第一次点击触发回调事件。|
1899| onLongPress | Callback\<[GestureEvent](ts-gesture-common.md#gestureevent对象说明)\>  | 否 | 是    | [GestureEvent](ts-gesture-common.md#gestureevent对象说明)为用户长按事件。<br/>长按完成时回调事件。 |
1900
1901## KeyboardOptions<sup>12+</sup>
1902
1903设置自定义键盘是否支持避让功能。
1904
1905**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1906
1907**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1908
1909| 名称            | 类型                 | 只读 | 可选   | 说明                               |
1910| --------------- | ---------------  |---- | -------|-----------------------------  |
1911| supportAvoidance | boolean | 否 | 是 | 设置自定义键盘是否支持避让功能。默认值为 `false`,表示不支持避让;`true` 表示支持避让。 |
1912
1913## SubmitCallback<sup>12+</sup>
1914
1915type SubmitCallback = (enterKey: EnterKeyType, event: SubmitEvent) => void
1916
1917软键盘按下回车键时的回调事件。
1918
1919**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1920
1921**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1922
1923**参数:**
1924
1925| 参数名   | 类型                                                         | 必填 | 说明                                                     |
1926| -------- | ------------------------------------------------------------ | ---- | -------------------------------------------------------- |
1927| enterKey | [EnterKeyType](ts-basic-components-textinput.md#enterkeytype枚举说明)             | 是   | 软键盘输入法回车键类型。具体类型见EnterKeyType枚举说明。 |
1928| event    | [SubmitEvent](ts-basic-components-textinput.md#submitevent11) | 是   | 当提交的时候,提供保持组件编辑状态的方法。EnterKeyType指定为NEW_LINE时,默认保持编辑态。         |
1929
1930## MenuOnAppearCallback<sup>12+</sup>
1931
1932type MenuOnAppearCallback = (start: number, end: number) => void
1933
1934自定义选择菜单弹出时触发的回调事件。
1935
1936**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1937
1938**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1939
1940**参数:**
1941
1942| 参数名  | 类型                                             | 必填 | 说明                                                     |
1943| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- |
1944| start | number | 是   | 选中内容的起始位置。 |
1945| end    | number         | 是   | 选中内容的终止位置。         |
1946
1947## MenuCallback<sup>15+</sup>
1948
1949type MenuCallback = (start: number, end: number) => void
1950
1951自定义选择菜单显示或隐藏时触发的回调事件。
1952
1953**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。
1954
1955**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1956
1957**参数:**
1958
1959| 参数名  | 类型                                             | 必填 | 说明                                                     |
1960| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- |
1961| start | number | 是   | 选中内容的起始位置。 |
1962| end    | number         | 是   | 选中内容的终止位置。         |
1963
1964## PasteEventCallback<sup>12+</sup>
1965
1966type PasteEventCallback = (event?: PasteEvent) => void
1967
1968粘贴完成前,触发回调。
1969
1970**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
1971
1972**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1973
1974**参数:**
1975
1976| 参数名     | 类型                                             | 必填 | 说明                                                     |
1977| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- |
1978| event  | [PasteEvent](#pasteevent11) | 否   | 定义用户粘贴事件。 |
1979
1980## OnHoverCallback<sup>14+</sup>
1981
1982type OnHoverCallback = (status: boolean, event: HoverEvent) => void
1983
1984鼠标悬浮触发回调。
1985
1986**原子化服务API:** 从API version 14开始,该接口支持在原子化服务中使用。
1987
1988**系统能力:** SystemCapability.ArkUI.ArkUI.Full
1989
1990**参数:**
1991
1992| 参数名     | 类型                                             | 必填 | 说明                                                     |
1993| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- |
1994| status  | boolean                            | 是   | 表示鼠标是否悬浮在组件上,鼠标进入组件时为true,离开组件时为false。|
1995| event   | [HoverEvent](ts-universal-events-hover.md#hoverevent10对象说明) | 是   | 设置悬浮事件。 |
1996
1997## RichEditorTextSpan
1998
1999文本Span信息。
2000
2001**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
2002
2003**系统能力:** SystemCapability.ArkUI.ArkUI.Full
2004
2005| 名称                            | 类型                                        | 只读 | 可选   | 说明                     |
2006| ----------------------------- | ---------------------------------------- | ---- | ---------|------------- |
2007| spanPosition                  | [RichEditorSpanPosition](#richeditorspanposition) | 否| 否    | Span位置。|
2008| value                         | string                                  | 否 | 否    | 文本Span内容。|
2009| textStyle                     | [RichEditorTextStyle](#richeditortextstyle) | 否| 是    | 文本Span样式信息。|
2010
2011## RichEditorImageSpan
2012
2013图片Span信息。
2014
2015**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
2016
2017**系统能力:** SystemCapability.ArkUI.ArkUI.Full
2018
2019| 名称               | 类型                                                                   | 只读 | 可选  | 说明               |
2020|------------------|-------------------------------------------------------------------|-----|----------|--------|
2021| spanPosition     | [RichEditorSpanPosition](#richeditorspanposition)                 | 否 | 否   | Span位置。|
2022| value            | [PixelMap](../../apis-image-kit/arkts-apis-image-PixelMap.md) \| [ResourceStr](ts-types.md#resourcestr)  | 否 | 否   | 图片内容。|
2023| imageStyle       | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | 否 | 是 | 图片样式。|
2024
2025## RichEditorUrlStyle<sup>19+</sup>
2026
2027Url信息。
2028
2029**原子化服务API:** 从API version 19开始,该接口支持在原子化服务中使用。
2030
2031**系统能力:** SystemCapability.ArkUI.ArkUI.Full
2032
2033| 名称    | 类型                                          | 只读 | 可选| 说明    |
2034|---------|---------------------------------------------|------|----|-----|
2035| url     | [ResourceStr](ts-types.md#resourcestr)      | 否 | 是   | url地址。<br/>默认值:undefined|
2036
2037## 示例
2038
2039### 示例1(更新文本样式)
2040通过[updateSpanStyle](#updatespanstyle)接口更新已有文本样式,更改样式后,使用[getSpans](#getspans)获取文本新的样式信息。
2041
2042```ts
2043// xxx.ets
2044@Entry
2045@Component
2046struct Index {
2047  controller: RichEditorController = new RichEditorController();
2048  options: RichEditorOptions = { controller: this.controller };
2049  private start: number = -1;
2050  private end: number = -1;
2051  @State message: string = "[-1, -1]";
2052  @State content: string = "";
2053
2054  build() {
2055    Column() {
2056      Column() {
2057        Text("selection range:").width("100%")
2058        Text() {
2059          Span(this.message)
2060        }.width("100%")
2061        Text("selection content:").width("100%")
2062        Text() {
2063          Span(this.content)
2064        }.width("100%")
2065      }
2066      .borderWidth(1)
2067      .borderColor(Color.Red)
2068      .width("100%")
2069      .height("20%")
2070
2071      Row() {
2072        Button("更新样式:加粗").onClick(() => {
2073          this.controller.updateSpanStyle({
2074            start: this.start,
2075            end: this.end,
2076            textStyle:
2077            {
2078              fontWeight: FontWeight.Bolder
2079            }
2080          })
2081        })
2082        Button("获取选择内容").onClick(() => {
2083          this.content = "";
2084          this.controller.getSpans({
2085            start: this.start,
2086            end: this.end
2087          }).forEach(item => {
2088            if(typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined'){
2089              this.content += (item as RichEditorImageSpanResult).valueResourceStr;
2090              this.content += "\n";
2091            } else {
2092              if(typeof(item as RichEditorTextSpanResult)['symbolSpanStyle'] != 'undefined') {
2093                this.content += (item as RichEditorTextSpanResult).symbolSpanStyle?.fontSize;
2094                this.content += "\n";
2095              }else {
2096                this.content += (item as RichEditorTextSpanResult).value;
2097                this.content += "\n";
2098              }
2099            }
2100          })
2101        })
2102        Button("删除选择内容").onClick(() => {
2103          this.controller.deleteSpans({
2104            start: this.start,
2105            end: this.end
2106          })
2107          this.start = -1;
2108          this.end = -1;
2109          this.message = "[" + this.start + ", " + this.end + "]";
2110        })
2111      }
2112      .borderWidth(1)
2113      .borderColor(Color.Red)
2114      .width("100%")
2115      .height("10%")
2116
2117      Column() {
2118        RichEditor(this.options)
2119          .onReady(() => {
2120            this.controller.addTextSpan("012345",
2121              {
2122                style:
2123                {
2124                  fontColor: Color.Orange,
2125                  fontSize: 30
2126                }
2127              })
2128            this.controller.addSymbolSpan($r("sys.symbol.ohos_trash"),
2129              {
2130                style:
2131                {
2132                  fontSize: 30
2133                }
2134              })
2135            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
2136            this.controller.addImageSpan($r('app.media.startIcon'),
2137              {
2138                imageStyle:
2139                {
2140                  size: ["57px", "57px"]
2141                }
2142              })
2143            this.controller.addTextSpan("56789",
2144              {
2145                style:
2146                {
2147                  fontColor: Color.Black,
2148                  fontSize: 30
2149                }
2150              })
2151          })
2152          .onSelect((value: RichEditorSelection) => {
2153            this.start = value.selection[0];
2154            this.end = value.selection[1];
2155            this.message = "[" + this.start + ", " + this.end + "]";
2156          })
2157          .aboutToIMEInput((value: RichEditorInsertValue) => {
2158            console.info("---------------------- aboutToIMEInput ----------------------");
2159            console.info("insertOffset:" + value.insertOffset);
2160            console.info("insertValue:" + value.insertValue);
2161            return true;
2162          })
2163          .onIMEInputComplete((value: RichEditorTextSpanResult) => {
2164            console.info("---------------------- onIMEInputComplete ---------------------");
2165            console.info("spanIndex:" + value.spanPosition.spanIndex);
2166            console.info("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]");
2167            console.info("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]");
2168            console.info("value:" + value.value);
2169          })
2170          .aboutToDelete((value: RichEditorDeleteValue) => {
2171            console.info("---------------------- aboutToDelete --------------------------");
2172            console.info("offset:" + value.offset);
2173            console.info("direction:" + value.direction);
2174            console.info("length:" + value.length);
2175            value.richEditorDeleteSpans.forEach(item => {
2176              console.info("---------------------- item --------------------------");
2177              console.info("spanIndex:" + item.spanPosition.spanIndex);
2178              console.info("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]");
2179              console.info("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]");
2180              if (typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
2181                console.info("image:" + (item as RichEditorImageSpanResult).valueResourceStr);
2182              } else {
2183                console.info("text:" + (item as RichEditorTextSpanResult).value);
2184              }
2185            })
2186            return true;
2187          })
2188          .onDeleteComplete(() => {
2189            console.info("---------------------- onDeleteComplete ------------------------");
2190          })
2191          .placeholder("input...", {
2192            fontColor: Color.Gray,
2193            font: {
2194              size: 16,
2195              weight: FontWeight.Normal,
2196              family: "HarmonyOS Sans",
2197              style: FontStyle.Normal
2198            }
2199          })
2200          .borderWidth(1)
2201          .borderColor(Color.Green)
2202          .width("100%")
2203          .height("30%")
2204      }
2205      .borderWidth(1)
2206      .borderColor(Color.Red)
2207      .width("100%")
2208      .height("70%")
2209    }
2210  }
2211}
2212```
2213![richeditor](figures/richeditor.gif)
2214
2215### 示例2(绑定自定义键盘)
2216通过[customKeyboard](#customkeyboard)给组件绑定自定义键盘。
2217
2218```ts
2219// xxx.ets
2220@Entry
2221@Component
2222struct RichEditorExample {
2223  controller: RichEditorController = new RichEditorController();
2224
2225  // 自定义键盘组件
2226  @Builder
2227  CustomKeyboardBuilder() {
2228    Column() {
2229      Grid() {
2230        ForEach(['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'], (item: string) => {
2231          GridItem() {
2232            Button(item).width(110).onClick(() => {
2233              this.controller.addTextSpan(item + '', {
2234                offset: this.controller.getCaretOffset(),
2235                style:
2236                {
2237                  fontColor: Color.Orange,
2238                  fontSize: 30
2239                }
2240              })
2241            })
2242          }
2243        })
2244      }.maxCount(3).columnsGap(10).rowsGap(10).padding(5)
2245    }.backgroundColor(Color.Gray)
2246  }
2247
2248  build() {
2249    Column() {
2250      RichEditor({ controller: this.controller })// 绑定自定义键盘
2251        .customKeyboard(this.CustomKeyboardBuilder())
2252        .border({ width: 1 })
2253        .borderWidth(1)
2254        .borderColor(Color.Red)
2255        .margin(10)
2256        .height(200)
2257        .width("100%")
2258    }
2259  }
2260}
2261```
2262
2263![customKeyboard](figures/richEditorCustomKeyboard.gif)
2264
2265### 示例3(绑定自定义菜单)
2266通过[bindSelectionMenu](#bindselectionmenu)给组件绑定自定义菜单。
2267
2268示例中的粘贴菜单项涉及读取剪贴板数据,因此需按规范[申请访问剪贴板权限](../../../basic-services/pasteboard/get-pastedata-permission-guidelines.md)。
2269
2270```ts
2271// xxx.ets
2272import { BusinessError, pasteboard } from '@kit.BasicServicesKit';
2273
2274export interface SelectionMenuTheme {
2275  imageSize: number;
2276  buttonSize: number;
2277  menuSpacing: number;
2278  editorOptionMargin: number;
2279  expandedOptionPadding: number;
2280  defaultMenuWidth: number;
2281  imageFillColor: Resource;
2282  backGroundColor: Resource;
2283  iconBorderRadius: Resource;
2284  containerBorderRadius: Resource;
2285  cutIcon: Resource;
2286  copyIcon: Resource;
2287  pasteIcon: Resource;
2288  selectAllIcon: Resource;
2289  shareIcon: Resource;
2290  translateIcon: Resource;
2291  searchIcon: Resource;
2292  arrowDownIcon: Resource;
2293  iconPanelShadowStyle: ShadowStyle;
2294  iconFocusBorderColor: Resource;
2295}
2296
2297export const defaultTheme: SelectionMenuTheme = {
2298  imageSize: 24,
2299  buttonSize: 48,
2300  menuSpacing: 8,
2301  editorOptionMargin: 1,
2302  expandedOptionPadding: 3,
2303  defaultMenuWidth: 256,
2304  imageFillColor: $r('sys.color.ohos_id_color_primary'),
2305  backGroundColor: $r('sys.color.ohos_id_color_dialog_bg'),
2306  iconBorderRadius: $r('sys.float.ohos_id_corner_radius_default_m'),
2307  containerBorderRadius: $r('sys.float.ohos_id_corner_radius_card'),
2308  cutIcon: $r("sys.media.ohos_ic_public_cut"),
2309  copyIcon: $r("sys.media.ohos_ic_public_copy"),
2310  pasteIcon: $r("sys.media.ohos_ic_public_paste"),
2311  selectAllIcon: $r("sys.media.ohos_ic_public_select_all"),
2312  shareIcon: $r("sys.media.ohos_ic_public_share"),
2313  translateIcon: $r("sys.media.ohos_ic_public_translate_c2e"),
2314  searchIcon: $r("sys.media.ohos_ic_public_search_filled"),
2315  arrowDownIcon: $r("sys.media.ohos_ic_public_arrow_down"),
2316  iconPanelShadowStyle: ShadowStyle.OUTER_DEFAULT_MD,
2317  iconFocusBorderColor: $r('sys.color.ohos_id_color_focused_outline')
2318}
2319
2320@Entry
2321@Component
2322struct SelectionMenu {
2323  @State message: string = 'Hello World';
2324  @State textSize: number = 40;
2325  @State sliderShow: boolean = false;
2326  @State start: number = -1;
2327  @State end: number = -1;
2328  @State colorTransparent: Color = Color.Transparent;
2329  controller: RichEditorController = new RichEditorController();
2330  options: RichEditorOptions = { controller: this.controller };
2331  // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
2332  private iconArr: Array<Resource> =
2333    [$r('app.media.startIcon'), $r('app.media.startIcon'), $r('app.media.startIcon'),
2334    $r('app.media.startIcon'), $r('app.media.startIcon')];
2335  @State iconBgColor: ResourceColor[] = new Array(this.iconArr.length).fill(this.colorTransparent);
2336  @State pasteEnable: boolean = false;
2337  @State visibilityValue: Visibility = Visibility.Visible;
2338  @State textStyle: RichEditorTextStyle = {};
2339  private fontWeightTable: string[] = ["100", "200", "300", "400", "500", "600", "700", "800", "900", "bold", "normal", "bolder", "lighter", "medium", "regular"];
2340  private theme: SelectionMenuTheme = defaultTheme;
2341
2342  aboutToAppear() {
2343    if (this.controller) {
2344      let richEditorSelection = this.controller.getSelection();
2345      if (richEditorSelection) {
2346        let start = richEditorSelection.selection[0];
2347        let end = richEditorSelection.selection[1];
2348        if (start === 0 && this.controller.getSpans({ start: end + 1, end: end + 1 }).length === 0) {
2349          this.visibilityValue = Visibility.None;
2350        } else {
2351          this.visibilityValue = Visibility.Visible;
2352        }
2353      }
2354    }
2355    let sysBoard = pasteboard.getSystemPasteboard()
2356    try {
2357      if (sysBoard && sysBoard.hasDataSync()) {
2358        this.pasteEnable = true
2359      } else {
2360        this.pasteEnable = false
2361      }
2362    } catch (err) {
2363      console.error('Failed to check the PasteData. Cause:' + err.message)
2364    }
2365  }
2366
2367  build() {
2368    Column() {
2369      Column() {
2370        RichEditor(this.options)
2371          .onReady(() => {
2372            this.controller.addTextSpan(this.message, { style: { fontColor: Color.Orange, fontSize: 30 } })
2373          })
2374          .onSelect((value: RichEditorSelection) => {
2375            if (value.selection[0] == -1 && value.selection[1] == -1) {
2376              return;
2377            }
2378            this.start = value.selection[0];
2379            this.end = value.selection[1];
2380          })
2381          .bindSelectionMenu(RichEditorSpanType.TEXT, this.panel, ResponseType.LongPress, { onDisappear: () => {
2382            this.sliderShow = false;
2383          }})
2384          .bindSelectionMenu(RichEditorSpanType.TEXT, this.panel, ResponseType.RightClick, { onDisappear: () => {
2385            this.sliderShow = false;
2386          }})
2387          .bindSelectionMenu(RichEditorSpanType.IMAGE, this.panel, ResponseType.LongPress, {
2388            menuType : MenuType.PREVIEW_MENU,
2389            previewMenuOptions : {
2390              hapticFeedbackMode : HapticFeedbackMode.ENABLED
2391            }
2392          })
2393          .borderWidth(1)
2394          .borderColor(Color.Red)
2395          .width(200)
2396          .height(200)
2397      }.width('100%').backgroundColor(Color.White)
2398    }.height('100%')
2399  }
2400
2401  PushDataToPasteboard(richEditorSelection: RichEditorSelection) {
2402    let sysBoard = pasteboard.getSystemPasteboard();
2403    let pasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, '');
2404    if (richEditorSelection.spans && richEditorSelection.spans.length > 0) {
2405      let count = richEditorSelection.spans.length;
2406      for (let i = count - 1; i >= 0; i--) {
2407        let item = richEditorSelection.spans[i]
2408        if ((item as RichEditorTextSpanResult)?.textStyle) {
2409          let span = item as RichEditorTextSpanResult;
2410          let style = span.textStyle;
2411          let data = pasteboard.createRecord(pasteboard.MIMETYPE_TEXT_PLAIN, span.value.substring(span.offsetInSpan[0], span.offsetInSpan[1]));
2412          let prop = pasteData.getProperty();
2413          let temp: Record<string, Object> = {
2414            'color': style.fontColor,
2415            'size': style.fontSize,
2416            'style': style.fontStyle,
2417            'weight': this.fontWeightTable[style.fontWeight],
2418            'fontFamily': style.fontFamily,
2419            'decorationType': style.decoration.type,
2420            'decorationColor': style.decoration.color
2421          };
2422          prop.additions[i] = temp;
2423          pasteData.addRecord(data)
2424          pasteData.setProperty(prop)
2425        }
2426      }
2427    }
2428    sysBoard.clearData()
2429    sysBoard.setData(pasteData).then(() => {
2430      console.info('SelectionMenu copy option, Succeeded in setting PasteData.');
2431      this.pasteEnable = true;
2432    }).catch((err: BusinessError) => {
2433      console.error('SelectionMenu copy option, Failed to set PasteData. Cause:' + err.message);
2434    })
2435  }
2436
2437  PopDataFromPasteboard(richEditorSelection: RichEditorSelection) {
2438    let start = richEditorSelection.selection[0];
2439    let end = richEditorSelection.selection[1];
2440    if (start == end && this.controller) {
2441      start = this.controller.getCaretOffset();
2442      end = this.controller.getCaretOffset();
2443    }
2444    let moveOffset = 0;
2445    let sysBoard = pasteboard.getSystemPasteboard();
2446    sysBoard.getData((err, data) => {
2447      if (err) {
2448        return;
2449      }
2450      let count = data.getRecordCount();
2451      for (let i = 0; i < count; i++) {
2452        const element = data.getRecord(i);
2453        let tex: RichEditorTextStyle = {
2454          fontSize: 16,
2455          fontColor: Color.Black,
2456          fontWeight: FontWeight.Normal,
2457          fontFamily: "HarmonyOS Sans",
2458          fontStyle: FontStyle.Normal,
2459          decoration: { type: TextDecorationType.None, color: "#FF000000", style: TextDecorationStyle.SOLID }
2460        }
2461        if (data.getProperty() && data.getProperty().additions[i]) {
2462          const tmp = data.getProperty().additions[i] as Record<string, Object | undefined>;
2463          if (tmp.color) {
2464            tex.fontColor = tmp.color as ResourceColor;
2465          }
2466          if (tmp.size) {
2467            tex.fontSize = tmp.size as Length | number;
2468          }
2469          if (tmp.style) {
2470            tex.fontStyle = tmp.style as FontStyle;
2471          }
2472          if (tmp.weight) {
2473            tex.fontWeight = tmp.weight as number | FontWeight | string;
2474          }
2475          if (tmp.fontFamily) {
2476            tex.fontFamily = tmp.fontFamily as ResourceStr;
2477          }
2478          if (tmp.decorationType && tex.decoration) {
2479            tex.decoration.type = tmp.decorationType as TextDecorationType;
2480          }
2481          if (tmp.decorationColor && tex.decoration) {
2482            tex.decoration.color = tmp.decorationColor as ResourceColor;
2483          }
2484          if (tex.decoration) {
2485            tex.decoration = { type: tex.decoration.type, color: tex.decoration.color };
2486          }
2487        }
2488        if (element && element.plainText && element.mimeType === pasteboard.MIMETYPE_TEXT_PLAIN && this.controller) {
2489          this.controller.addTextSpan(element.plainText,
2490            {
2491              style: tex,
2492              offset: start + moveOffset
2493            }
2494          )
2495          moveOffset += element.plainText.length;
2496        }
2497      }
2498      if (this.controller) {
2499        this.controller.setCaretOffset(start + moveOffset)
2500        this.controller.closeSelectionMenu()
2501      }
2502      if (start != end && this.controller) {
2503        this.controller.deleteSpans({ start: start + moveOffset, end: end + moveOffset })
2504      }
2505    })
2506  }
2507
2508  @Builder
2509  panel() {
2510    Column() {
2511      this.iconPanel()
2512      if (!this.sliderShow) {
2513        this.SystemMenu()
2514      } else {
2515        this.sliderPanel()
2516      }
2517    }.width(256)
2518  }
2519
2520  @Builder iconPanel() {
2521    Column() {
2522      Row({ space: 2 }) {
2523        ForEach(this.iconArr, (item:Resource, index ?: number) => {
2524          Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
2525            Image(item).fillColor(this.theme.imageFillColor).width(24).height(24).focusable(true).draggable(false)
2526          }
2527          .borderRadius(this.theme.iconBorderRadius)
2528          .width(this.theme.buttonSize)
2529          .height(this.theme.buttonSize)
2530          .onClick(() => {
2531            if (index as number == 0) {
2532              this.sliderShow = false;
2533              if (this.controller) {
2534                let selection = this.controller.getSelection();
2535                let spans = selection.spans;
2536                spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => {
2537                  if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') {
2538                    let span = item as RichEditorTextSpanResult;
2539                    this.textStyle = span.textStyle;
2540                    let start = span.offsetInSpan[0];
2541                    let end = span.offsetInSpan[1];
2542                    let offset = span.spanPosition.spanRange[0];
2543                    if (this.textStyle.fontWeight != 11) {
2544                      this.textStyle.fontWeight = FontWeight.Bolder;
2545                    } else {
2546                      this.textStyle.fontWeight = FontWeight.Normal;
2547                    }
2548                    this.controller.updateSpanStyle({
2549                      start: offset + start,
2550                      end: offset + end,
2551                      textStyle: this.textStyle
2552                    })
2553                  }
2554                })
2555              }
2556            } else if (index as number == 1) {
2557              this.sliderShow = false;
2558              if (this.controller) {
2559                let selection = this.controller.getSelection();
2560                let spans = selection.spans;
2561                spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => {
2562                  if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') {
2563                    let span = item as RichEditorTextSpanResult;
2564                    this.textStyle = span.textStyle;
2565                    let start = span.offsetInSpan[0];
2566                    let end = span.offsetInSpan[1];
2567                    let offset = span.spanPosition.spanRange[0];
2568                    if (this.textStyle.fontStyle == FontStyle.Italic) {
2569                      this.textStyle.fontStyle = FontStyle.Normal;
2570                    } else {
2571                      this.textStyle.fontStyle = FontStyle.Italic;
2572                    }
2573                    this.controller.updateSpanStyle({
2574                      start: offset + start,
2575                      end: offset + end,
2576                      textStyle: this.textStyle
2577                    })
2578                  }
2579                })
2580              }
2581            } else if (index as number == 2) {
2582              this.sliderShow = false;
2583              if (this.controller) {
2584                let selection = this.controller.getSelection();
2585                let spans = selection.spans;
2586                spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => {
2587                  if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') {
2588                    let span = item as RichEditorTextSpanResult;
2589                    this.textStyle = span.textStyle;
2590                    let start = span.offsetInSpan[0];
2591                    let end = span.offsetInSpan[1];
2592                    let offset = span.spanPosition.spanRange[0];
2593                    if (this.textStyle.decoration) {
2594                      if (this.textStyle.decoration.type == TextDecorationType.Underline) {
2595                        this.textStyle.decoration.type = TextDecorationType.None;
2596                      } else {
2597                        this.textStyle.decoration.type = TextDecorationType.Underline;
2598                      }
2599                    } else {
2600                      this.textStyle.decoration = { type: TextDecorationType.Underline, color: Color.Black, style: TextDecorationStyle.SOLID };
2601                    }
2602                    this.controller.updateSpanStyle({
2603                      start: offset + start,
2604                      end: offset + end,
2605                      textStyle: this.textStyle
2606                    })
2607                  }
2608                })
2609              }
2610            } else if (index as number == 3) {
2611              this.sliderShow = !this.sliderShow;
2612            } else if (index as number == 4) {
2613              this.sliderShow = false;
2614              if (this.controller) {
2615                let selection = this.controller.getSelection();
2616                let spans = selection.spans;
2617                spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => {
2618                  if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') {
2619                    let span = item as RichEditorTextSpanResult;
2620                    this.textStyle = span.textStyle;
2621                    let start = span.offsetInSpan[0];
2622                    let end = span.offsetInSpan[1];
2623                    let offset = span.spanPosition.spanRange[0];
2624                    if (this.textStyle.fontColor == Color.Orange || this.textStyle.fontColor == '#FFFFA500') {
2625                      this.textStyle.fontColor = Color.Black;
2626                    } else {
2627                      this.textStyle.fontColor = Color.Orange;
2628                    }
2629                    this.controller.updateSpanStyle({
2630                      start: offset + start,
2631                      end: offset + end,
2632                      textStyle: this.textStyle
2633                    })
2634                  }
2635                })
2636              }
2637            }
2638          })
2639          .onTouch((event?: TouchEvent | undefined) => {
2640            if(event != undefined){
2641              if (event.type === TouchType.Down) {
2642                this.iconBgColor[index as number] = $r('sys.color.ohos_id_color_click_effect');
2643              }
2644              if (event.type === TouchType.Up) {
2645                this.iconBgColor[index as number] = this.colorTransparent;
2646              }
2647            }
2648          })
2649          .onHover((isHover?: boolean, event?: HoverEvent) => {
2650            this.iconBgColor.forEach((icon:ResourceColor, index1) => {
2651              this.iconBgColor[index1] = this.colorTransparent;
2652            })
2653            if(isHover != undefined) {
2654              this.iconBgColor[index as number] = $r('sys.color.ohos_id_color_hover');
2655            }
2656          })
2657          .backgroundColor(this.iconBgColor[index as number])
2658        })
2659      }
2660    }
2661    .clip(true)
2662    .width(this.theme.defaultMenuWidth)
2663    .padding(this.theme.expandedOptionPadding)
2664    .borderRadius(this.theme.containerBorderRadius)
2665    .margin({ bottom: this.theme.menuSpacing })
2666    .backgroundColor(this.theme.backGroundColor)
2667    .shadow(this.theme.iconPanelShadowStyle)
2668  }
2669
2670  @Builder
2671  SystemMenu() {
2672    Column() {
2673      Menu() {
2674        if (this.controller) {
2675          MenuItemGroup() {
2676            MenuItem({ startIcon: this.theme.cutIcon, content: "剪切", labelInfo: "Ctrl+X" })
2677              .onClick(() => {
2678                if (!this.controller) {
2679                  return
2680                }
2681                let richEditorSelection = this.controller.getSelection();
2682                this.PushDataToPasteboard(richEditorSelection);
2683                this.controller.deleteSpans({
2684                  start: richEditorSelection.selection[0],
2685                  end: richEditorSelection.selection[1]
2686                })
2687              })
2688            MenuItem({ startIcon: this.theme.copyIcon, content: "复制", labelInfo: "Ctrl+C" })
2689              .onClick(() => {
2690                if (!this.controller) {
2691                  return;
2692                }
2693                let richEditorSelection = this.controller.getSelection();
2694                this.PushDataToPasteboard(richEditorSelection)
2695                this.controller.closeSelectionMenu()
2696              })
2697            MenuItem({ startIcon: this.theme.pasteIcon, content: "粘贴", labelInfo: "Ctrl+V" })
2698              .enabled(this.pasteEnable)
2699              .onClick(() => {
2700                if (!this.controller) {
2701                  return;
2702                }
2703                let richEditorSelection = this.controller.getSelection();
2704                this.PopDataFromPasteboard(richEditorSelection)
2705              })
2706            MenuItem({ startIcon: this.theme.selectAllIcon, content: "全选", labelInfo: "Ctrl+A" })
2707              .visibility(this.visibilityValue)
2708              .onClick(() => {
2709                if (!this.controller) {
2710                  return;
2711                }
2712                this.controller.setSelection(-1, -1)
2713                this.visibilityValue = Visibility.None;
2714              })
2715            MenuItem({ startIcon: this.theme.shareIcon, content: "分享", labelInfo: "" })
2716              .enabled(false)
2717            MenuItem({ startIcon: this.theme.translateIcon, content: "翻译", labelInfo: "" })
2718              .enabled(false)
2719            MenuItem({ startIcon: this.theme.searchIcon, content: "搜索", labelInfo: "" })
2720              .enabled(false)
2721          }
2722        }
2723      }
2724      .onVisibleAreaChange([0.0, 1.0], () => {
2725        if (!this.controller) {
2726          return;
2727        }
2728        let richEditorSelection = this.controller.getSelection();
2729        let start = richEditorSelection.selection[0];
2730        let end = richEditorSelection.selection[1];
2731        if (start === 0 && this.controller.getSpans({ start: end + 1, end: end + 1 }).length === 0) {
2732          this.visibilityValue = Visibility.None;
2733        } else {
2734          this.visibilityValue = Visibility.Visible;
2735        }
2736      })
2737      .radius(this.theme.containerBorderRadius)
2738      .clip(true)
2739      .backgroundColor(Color.White)
2740      .width(this.theme.defaultMenuWidth)
2741    }
2742    .width(this.theme.defaultMenuWidth)
2743  }
2744
2745  @Builder sliderPanel() {
2746    Column() {
2747      Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
2748        Text('A').fontSize(15)
2749        Slider({ value: this.textSize, step: 10, style: SliderStyle.InSet })
2750          .width(210)
2751          .onChange((value: number, mode: SliderChangeMode) => {
2752            if (this.controller) {
2753              let selection = this.controller.getSelection();
2754              if (mode == SliderChangeMode.End) {
2755                if (this.textSize == undefined) {
2756                  this.textSize = 0;
2757                }
2758                let spans = selection.spans;
2759                spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => {
2760                  if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') {
2761                    this.textSize = Math.max(this.textSize, (item as RichEditorTextSpanResult).textStyle.fontSize);
2762                  }
2763                })
2764              }
2765              if (mode == SliderChangeMode.Moving || mode == SliderChangeMode.Click) {
2766                this.start = selection.selection[0];
2767                this.end = selection.selection[1];
2768                this.textSize = value;
2769                this.controller.updateSpanStyle({
2770                  start: this.start,
2771                  end: this.end,
2772                  textStyle: { fontSize: this.textSize }
2773                })
2774              }
2775            }
2776          })
2777        Text('A').fontSize(20).fontWeight(FontWeight.Medium)
2778      }.borderRadius(this.theme.containerBorderRadius)
2779    }
2780    .shadow(ShadowStyle.OUTER_DEFAULT_MD)
2781    .backgroundColor(Color.White)
2782    .borderRadius(this.theme.containerBorderRadius)
2783    .padding(15)
2784    .height(48)
2785  }
2786}
2787```
2788> **说明:**
2789>
2790> 系统暂未预置加粗、斜体等图标,示例代码使用系统默认图标,开发者使用时需自行替换iconArr中的资源。
2791
2792![selectionMenu](figures/richEditorSelectionMenu.png)
2793
2794### 示例4(更新图片样式)
2795通过[updateSpanStyle](#updatespanstyle)接口更新图片样式。
2796
2797```ts
2798// xxx.ets
2799@Entry
2800@Component
2801struct Index {
2802  controller: RichEditorController = new RichEditorController();
2803  options: RichEditorOptions = { controller: this.controller };
2804  private start: number = -1;
2805  private end: number = -1;
2806  @State message: string = "[-1, -1]";
2807  @State content: string = "";
2808  @State paddingVal: number = 5;
2809  @State borderRad: number = 4;
2810
2811  build() {
2812    Column() {
2813      Column() {
2814        Text("selection range:").width("100%")
2815        Text() {
2816          Span(this.message)
2817        }.width("100%")
2818        Text("selection content:").width("100%")
2819        Text() {
2820          Span(this.content)
2821        }.width("100%")
2822      }
2823      .borderWidth(1)
2824      .borderColor(Color.Red)
2825      .width("100%")
2826      .height("20%")
2827
2828      Row() {
2829        Button("updateSpanStyle1")
2830          .fontSize(12)
2831          .onClick(() => {
2832            this.controller.updateSpanStyle({
2833              start: this.start,
2834              textStyle:
2835              {
2836                fontWeight: FontWeight.Bolder
2837              },
2838              imageStyle: {
2839                size: ["80px", "80px"],
2840                layoutStyle: {
2841                  borderRadius: undefined,
2842                  margin: undefined
2843                }
2844              }
2845            })
2846          })
2847
2848        Button("updateSpanStyle2")
2849          .fontSize(12)
2850          .onClick(() => {
2851            this.controller.updateSpanStyle({
2852              start: this.start,
2853              textStyle:
2854              {
2855                fontWeight: FontWeight.Bolder
2856              },
2857              imageStyle: {
2858                size: ["70px", "70px"],
2859                layoutStyle: {
2860                  borderRadius: { topLeft: '100px', topRight: '20px', bottomLeft: '100px', bottomRight: '20px' },
2861                  margin: { left: '30px', top: '20px', right: '20px', bottom: '20px' }
2862                }
2863              }
2864            })
2865          })
2866
2867        Button("updateSpanStyle3")
2868          .fontSize(12)
2869          .onClick(() => {
2870            this.controller.updateSpanStyle({
2871              start: this.start,
2872              textStyle:
2873              {
2874                fontWeight: FontWeight.Bolder
2875              },
2876              imageStyle: {
2877                size: ["60px", "60px"],
2878                layoutStyle: {
2879                  borderRadius: '-10px',
2880                  margin: '-10px'
2881                }
2882              }
2883            })
2884          })
2885      }
2886      .borderWidth(1)
2887      .borderColor(Color.Red)
2888      .width("100%")
2889      .height("10%")
2890
2891      Row() {
2892        Button('addImageSpan1')
2893          .fontSize(12)
2894          .onClick(() => {
2895            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
2896            this.controller.addImageSpan($r('app.media.startIcon'), {
2897              imageStyle: {
2898                size: ["80px", "80px"],
2899                layoutStyle: {
2900                  borderRadius: '50px',
2901                  margin: '40px'
2902                }
2903              }
2904            })
2905          })
2906
2907        Button('addImageSpan2')
2908          .fontSize(12)
2909          .onClick(() => {
2910            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
2911            this.controller.addImageSpan($r('app.media.startIcon'), {
2912              imageStyle: {
2913                size: ["100px", "100px"],
2914                verticalAlign: ImageSpanAlignment.BOTTOM,
2915                layoutStyle: {
2916                  borderRadius: undefined,
2917                  margin: undefined
2918                }
2919              }
2920            })
2921          })
2922
2923        Button('addImageSpan3')
2924          .fontSize(12)
2925          .onClick(() => {
2926            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
2927            this.controller.addImageSpan($r('app.media.startIcon'), {
2928              imageStyle: {
2929                size: ["60px", "60px"],
2930                verticalAlign: ImageSpanAlignment.BOTTOM,
2931                layoutStyle: {
2932                  borderRadius: { topLeft: '10px', topRight: '20px', bottomLeft: '30px', bottomRight: '40px' },
2933                  margin: { left: '10px', top: '20px', right: '30px', bottom: '40px' }
2934                }
2935              }
2936            })
2937          })
2938      }
2939      .borderWidth(1)
2940      .borderColor(Color.Red)
2941      .width("100%")
2942      .height("10%")
2943
2944      Column() {
2945        RichEditor(this.options)
2946          .onReady(() => {
2947            this.controller.addTextSpan("0123456789",
2948              {
2949                style:
2950                {
2951                  fontColor: Color.Orange,
2952                  fontSize: 30
2953                }
2954              })
2955
2956            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
2957            this.controller.addImageSpan($r('app.media.startIcon'),
2958              {
2959                imageStyle:
2960                {
2961                  size: ["60px", "60px"],
2962                  verticalAlign: ImageSpanAlignment.BOTTOM,
2963                  layoutStyle: {
2964                    borderRadius: { topLeft: '10px', topRight: '20px', bottomLeft: '30px', bottomRight: '40px' },
2965                    margin: { left: '10px', top: '20px', right: '30px', bottom: '40px' }
2966                  }
2967                }
2968              })
2969
2970            this.controller.addTextSpan("0123456789",
2971              {
2972                style:
2973                {
2974                  fontColor: Color.Black,
2975                  fontSize: 30
2976                }
2977              })
2978          })
2979          .onSelect((value: RichEditorSelection) => {
2980            this.start = value.selection[0];
2981            this.end = value.selection[1];
2982            this.message = "[" + this.start + ", " + this.end + "]";
2983          })
2984          .aboutToIMEInput((value: RichEditorInsertValue) => {
2985            console.info("---------------------- aboutToIMEInput ----------------------");
2986            console.info("insertOffset:" + value.insertOffset);
2987            console.info("insertValue:" + value.insertValue);
2988            return true;
2989          })
2990          .onIMEInputComplete((value: RichEditorTextSpanResult) => {
2991            console.info("---------------------- onIMEInputComplete ---------------------");
2992            console.info("spanIndex:" + value.spanPosition.spanIndex);
2993            console.info("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]");
2994            console.info("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]");
2995            console.info("value:" + value.value);
2996          })
2997          .aboutToDelete((value: RichEditorDeleteValue) => {
2998            console.info("---------------------- aboutToDelete --------------------------");
2999            console.info("offset:" + value.offset);
3000            console.info("direction:" + value.direction);
3001            console.info("length:" + value.length);
3002            value.richEditorDeleteSpans.forEach(item => {
3003              console.info("---------------------- item --------------------------");
3004              console.info("spanIndex:" + item.spanPosition.spanIndex);
3005              console.info("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]");
3006              console.info("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]");
3007              if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
3008                console.info("image:" + (item as RichEditorImageSpanResult).valueResourceStr);
3009              } else {
3010                console.info("text:" + (item as RichEditorTextSpanResult).value);
3011              }
3012            })
3013            return true;
3014          })
3015          .onDeleteComplete(() => {
3016            console.info("---------------------- onDeleteComplete ------------------------");
3017          })
3018          .borderWidth(1)
3019          .borderColor(Color.Green)
3020          .width("100%")
3021          .height('80.00%')
3022      }
3023      .borderWidth(1)
3024      .borderColor(Color.Red)
3025      .width("100%")
3026      .height("70%")
3027    }
3028  }
3029}
3030```
3031![ImageSpanStyle](figures/richEditorImageSpanStyle.gif)
3032
3033### 示例5(Span绑定手势事件)
3034为Span绑定[gesture](#richeditorgesture11)回调。
3035
3036```ts
3037// xxx.ets
3038@Entry
3039@Component
3040struct Index {
3041  controller: RichEditorController = new RichEditorController();
3042  options: RichEditorOptions = { controller: this.controller };
3043  @State textFlag: string = "TextFlag";
3044
3045  build() {
3046    Column() {
3047      Column() {
3048        Text(this.textFlag)
3049          .copyOption(CopyOptions.InApp)
3050          .fontSize(50)
3051          .height(150)
3052      }
3053      Divider()
3054      Column() {
3055        RichEditor(this.options)
3056          .onReady(() => {
3057            this.controller.addTextSpan('Area1\n', {
3058              style:
3059              {
3060                fontColor: Color.Orange,
3061                fontSize: 50,
3062              },
3063              gesture:
3064              {
3065                onClick: () => {
3066                  this.textFlag = "Area1 is onClick.";
3067                },
3068                onLongPress: () => {
3069                  this.textFlag = "Area1 is onLongPress.";
3070                }
3071              }
3072            })
3073
3074            this.controller.addTextSpan('Area2\n', {
3075              style:
3076              {
3077                fontColor: Color.Blue,
3078                fontSize: 50
3079              },
3080              gesture:
3081              {
3082                onClick: () => {
3083                  this.textFlag = "Area2 is onClick.";
3084                },
3085                onLongPress: () => {
3086                  this.textFlag = "Area2 is onLongPress.";
3087                }
3088              }
3089            })
3090
3091            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
3092            this.controller.addImageSpan($r('app.media.startIcon'),
3093              {
3094                imageStyle:
3095                {
3096                  size: ["100px", "100px"],
3097                  layoutStyle: {
3098                    margin: 5,
3099                    borderRadius: 15
3100                  }
3101                },
3102                gesture:
3103                {
3104                  onClick: () => {
3105                    this.textFlag = "ImageSpan is onClick.";
3106                  },
3107                  onLongPress: () => {
3108                    this.textFlag = "ImageSpan is onLongPress.";
3109                  }
3110                },
3111                onHover : (status) => {
3112                  this.textFlag = "ImageSpan is onHover :" + status;
3113                }
3114              })
3115          })
3116      }
3117      .borderWidth(1)
3118      .borderColor(Color.Red)
3119      .width("100%")
3120      .height("70%")
3121    }
3122  }
3123}
3124```
3125![OnClickAndLongPress](figures/richEditorGestureAndHover.gif)
3126
3127### 示例6(更新和获取段落样式)
3128通过[updateParagraphStyle](#updateparagraphstyle11)接口更新段落样式,通过[getParagraphs](#getparagraphs11)接口获取指定范围段落的信息。
3129
3130```ts
3131// xxx.ets
3132@Entry
3133@Component
3134struct Index {
3135  controller: RichEditorController = new RichEditorController();
3136  private spanParagraphs: RichEditorParagraphResult[] = [];
3137
3138  build() {
3139    Column() {
3140      RichEditor({ controller: this.controller })
3141        .onReady(() => {
3142          this.controller.addTextSpan("0123456789\n", {
3143            style: {
3144              fontColor: Color.Pink,
3145              fontSize: "32"
3146            },
3147            paragraphStyle: {
3148              textAlign: TextAlign.Start,
3149              textVerticalAlign: TextVerticalAlign.BASELINE,
3150              leadingMargin: 16
3151            }
3152          })
3153          this.controller.addTextSpan("0123456789")
3154        })
3155        .width("80%")
3156        .height("30%")
3157        .border({ width: 1, radius: 5 })
3158        .draggable(false)
3159
3160      Column({ space: 5 }) {
3161        Button("段落左对齐").onClick(() => {
3162          this.controller.updateParagraphStyle({ start: -1, end: -1,
3163            style: {
3164              textAlign: TextAlign.Start
3165            }
3166          })
3167        })
3168
3169        Button("段落右对齐").onClick(() => {
3170          this.controller.updateParagraphStyle({ start: -1, end: -1,
3171            style: {
3172              textAlign: TextAlign.End
3173            }
3174          })
3175        })
3176
3177        Button("段落居中").onClick(() => {
3178          this.controller.updateParagraphStyle({ start: -1, end: -1,
3179            style: {
3180              textAlign: TextAlign.Center
3181            }
3182          })
3183        })
3184
3185        Button("段落间距设置50").onClick(() => {
3186          this.controller.updateParagraphStyle({ start: -1, end: -1,
3187            style: {
3188              paragraphSpacing: 50
3189            }
3190          })
3191        })
3192        Divider()
3193        Button("getParagraphs").onClick(() => {
3194          this.spanParagraphs = this.controller.getParagraphs({ start: -1, end: -1 });
3195          console.info("RichEditor getParagraphs:" + JSON.stringify(this.spanParagraphs));
3196        })
3197
3198        Button("UpdateSpanStyle1").onClick(() => {
3199          this.controller.updateSpanStyle({ start: -1, end: -1,
3200            textStyle: {
3201              fontColor: Color.Brown,
3202              fontSize: 20
3203            }
3204          })
3205        })
3206
3207        Button("UpdateSpanStyle2").onClick(() => {
3208          this.controller.updateSpanStyle({ start: -1, end: -1,
3209            textStyle: {
3210              fontColor: Color.Green,
3211              fontSize: 30
3212            }
3213          })
3214        })
3215      }
3216    }
3217  }
3218}
3219```
3220![TextAlignAndGetParagraphInfo](figures/richEditorTextAlignAndGetParagraphInfo.gif)
3221
3222### 示例7(更新预设样式与缩进)
3223通过[setTypingStyle](#settypingstyle11)接口更新文本预设样式,通过[updateParagraphStyle](#updateparagraphstyle11)接口设置段落缩进。
3224
3225```ts
3226// xxx.ets
3227
3228const canvasWidth = 1000;
3229const canvasHeight = 100;
3230const Indentation = 40;
3231class LeadingMarginCreator {
3232  private settings: RenderingContextSettings = new RenderingContextSettings(true);
3233  private offscreenCanvas: OffscreenCanvas = new OffscreenCanvas(canvasWidth, canvasHeight);
3234  private offContext: OffscreenCanvasRenderingContext2D = this.offscreenCanvas.getContext("2d", this.settings);
3235  public static instance: LeadingMarginCreator = new LeadingMarginCreator();
3236
3237  // 获得字体字号级别,分别是从0到4级
3238  public getFontSizeLevel(fontSize: number) {
3239    const fontScaled: number = Number(fontSize) / 16;
3240
3241    enum FontSizeScaleThreshold {
3242      SMALL = 0.9,
3243      NORMAL = 1.1,
3244      LEVEL_1_LARGE = 1.2,
3245      LEVEL_2_LARGE = 1.4,
3246      LEVEL_3_LARGE = 1.5
3247    }
3248
3249    let fontSizeLevel: number = 1;
3250
3251    if (fontScaled < FontSizeScaleThreshold.SMALL) {
3252      fontSizeLevel = 0;
3253    } else if (fontScaled < FontSizeScaleThreshold.NORMAL) {
3254      fontSizeLevel = 1;
3255    } else if (fontScaled < FontSizeScaleThreshold.LEVEL_1_LARGE) {
3256      fontSizeLevel = 2;
3257    } else if (fontScaled < FontSizeScaleThreshold.LEVEL_2_LARGE) {
3258      fontSizeLevel = 3;
3259    } else if (fontScaled < FontSizeScaleThreshold.LEVEL_3_LARGE) {
3260      fontSizeLevel = 4;
3261    } else {
3262      fontSizeLevel = 1;
3263    }
3264
3265    return fontSizeLevel;
3266  }
3267  // 获得字体字号级别,分别是从0到4级
3268  public getmarginLevel(Width: number) {
3269    let marginlevel: number = 1;
3270    if (Width == 40) {
3271      marginlevel = 2.0;
3272    } else if (Width == 80) {
3273      marginlevel = 1.0;
3274    } else if (Width == 120) {
3275      marginlevel = 2/3;
3276    } else if (Width == 160) {
3277      marginlevel = 0.5;
3278    } else if (Width == 200) {
3279      marginlevel = 0.4;
3280    }
3281    return marginlevel;
3282  }
3283
3284  public genStrMark(fontSize: number, str: string): PixelMap {
3285    this.offContext = this.offscreenCanvas.getContext("2d", this.settings);
3286    this.clearCanvas()
3287    this.offContext.font = fontSize + 'vp sans-serif';
3288    this.offContext.fillText(str + '.', 0, fontSize * 0.9)
3289    return this.offContext.getPixelMap(0, 0, fontSize * (str.length + 1) / 1.75, fontSize)
3290  }
3291
3292  public genSquareMark(fontSize: number): PixelMap {
3293    this.offContext = this.offscreenCanvas.getContext("2d", this.settings);
3294    this.clearCanvas()
3295    const coordinate = fontSize * (1 - 1 / 1.5) / 2;
3296    const sideLength = fontSize / 1.5;
3297    this.offContext.fillRect(coordinate, coordinate, sideLength, sideLength)
3298    return this.offContext.getPixelMap(0, 0, fontSize, fontSize)
3299  }
3300
3301  // 生成圆圈符号
3302  public genCircleMark(fontSize: number, width: number, level?: number ): PixelMap {
3303    const indentLevel = level ?? 1;
3304    const offsetLevel = [22, 28, 32, 34, 38];
3305    const fontSizeLevel = this.getFontSizeLevel(fontSize);
3306    const marginlevel = this.getmarginLevel(width);
3307    const newCanvas = new OffscreenCanvas(canvasWidth, canvasHeight);
3308    const newOffContext: OffscreenCanvasRenderingContext2D = newCanvas.getContext("2d", this.settings);
3309    const centerCoordinate = 50;
3310    const radius = 10;
3311    this.clearCanvas()
3312    newOffContext.ellipse(100 * (indentLevel + 1) - centerCoordinate * marginlevel, offsetLevel[fontSizeLevel], radius * marginlevel, radius, 0, 0, 2 * Math.PI)
3313    newOffContext.fillStyle = '66FF0000';
3314    newOffContext.fill()
3315    return newOffContext.getPixelMap(0, 0, 100 + 100 * indentLevel, 100)
3316  }
3317
3318  private clearCanvas() {
3319    this.offContext.clearRect(0, 0, canvasWidth, canvasHeight)
3320  }
3321}
3322
3323@Entry
3324@Component
3325struct Index {
3326  controller: RichEditorController = new RichEditorController();
3327  options: RichEditorOptions = { controller: this.controller };
3328  private leadingMarkCreatorInstance = LeadingMarginCreator.instance;
3329  private fontNameRawFile: string = 'MiSans-Bold';
3330  @State fs: number = 30;
3331  @State cl: number = Color.Black;
3332  private leftMargin: Dimension = 0;
3333  private richEditorTextStyle: RichEditorTextStyle = {};
3334
3335  aboutToAppear() {
3336    this.getUIContext().getFont().registerFont({
3337      familyName: 'MiSans-Bold',
3338      familySrc: '/font/MiSans-Bold.ttf'
3339    })
3340  }
3341
3342  build() {
3343    Scroll() {
3344      Column() {
3345        RichEditor(this.options)
3346          .onReady(() => {
3347            this.controller.addTextSpan("0123456789\n",
3348              {
3349                style:
3350                {
3351                  fontWeight: 'medium',
3352                  fontFamily: this.fontNameRawFile,
3353                  fontColor: Color.Red,
3354                  fontSize: 50,
3355                  fontStyle: FontStyle.Italic,
3356                  decoration: { type: TextDecorationType.Underline, color: Color.Green }
3357                }
3358              })
3359
3360            this.controller.addTextSpan("abcdefg",
3361              {
3362                style:
3363                {
3364                  fontWeight: FontWeight.Lighter,
3365                  fontFamily: 'HarmonyOS Sans',
3366                  fontColor: 'rgba(0,128,0,0.5)',
3367                  fontSize: 30,
3368                  fontStyle: FontStyle.Normal,
3369                  decoration: { type: TextDecorationType.Overline, color: 'rgba(169, 26, 246, 0.50)' }
3370                }
3371              })
3372          })
3373          .borderWidth(1)
3374          .borderColor(Color.Green)
3375          .width("100%")
3376          .height("50%")
3377
3378        Row({ space: 5 }) {
3379          Button('setTypingStyle1')
3380            .fontSize(10)
3381            .onClick(() => {
3382              this.controller.setTypingStyle(
3383                {
3384                  fontWeight: 'medium',
3385                  fontFamily: this.fontNameRawFile,
3386                  fontColor: Color.Blue,
3387                  fontSize: 50,
3388                  fontStyle: FontStyle.Italic,
3389                  decoration: { type: TextDecorationType.Underline, color: Color.Green }
3390                })
3391            })
3392
3393          Button('setTypingStyle2')
3394            .fontSize(10)
3395            .onClick(() => {
3396              this.controller.setTypingStyle(
3397                {
3398                  fontWeight: FontWeight.Lighter,
3399                  fontFamily: 'HarmonyOS Sans',
3400                  fontColor: Color.Green,
3401                  fontSize: '30',
3402                  fontStyle: FontStyle.Normal,
3403                  decoration: { type: TextDecorationType.Overline, color: 'rgba(169, 26, 246, 0.50)' }
3404                })
3405            })
3406        }
3407        Divider()
3408        Button("getTypingStyle").onClick(() => {
3409          this.richEditorTextStyle = this.controller.getTypingStyle();
3410          console.info("RichEditor getTypingStyle:" + JSON.stringify(this.richEditorTextStyle));
3411        })
3412        Divider()
3413        Row({ space: 5 }) {
3414          Button("向右列表缩进").onClick(() => {
3415            let margin = Number(this.leftMargin);
3416            if (margin < 200) {
3417              margin += Indentation;
3418              this.leftMargin = margin;
3419            }
3420            this.controller.updateParagraphStyle({
3421              start: -10,
3422              end: -10,
3423              style: {
3424                leadingMargin : {
3425                  pixelMap : this.leadingMarkCreatorInstance.genCircleMark(100, margin, 1),
3426                  size: [margin, 40]
3427                }
3428              }
3429            })
3430          })
3431
3432          Button("向左列表缩进").onClick(() => {
3433            let margin = Number(this.leftMargin);
3434            if (margin > 0) {
3435              margin -= Indentation;
3436              this.leftMargin = margin;
3437            }
3438            this.controller.updateParagraphStyle({
3439              start: -10,
3440              end: -10,
3441              style: {
3442                leadingMargin : {
3443                  pixelMap : this.leadingMarkCreatorInstance.genCircleMark(100, margin, 1),
3444                  size: [margin, 40]
3445                }
3446              }
3447            })
3448          })
3449        }
3450        Divider()
3451        Row({ space: 5 }) {
3452          Button("向右空白缩进").onClick(() => {
3453            let margin = Number(this.leftMargin);
3454            if (margin < 200) {
3455              margin += Indentation;
3456              this.leftMargin = margin;
3457            }
3458            this.controller.updateParagraphStyle({
3459              start: -10,
3460              end: -10,
3461              style: {
3462                leadingMargin: margin
3463              }
3464            })
3465          })
3466
3467          Button("向左空白缩进").onClick(() => {
3468            let margin = Number(this.leftMargin)
3469            if (margin > 0) {
3470              margin -= Indentation;
3471              this.leftMargin = margin;
3472            }
3473            this.controller.updateParagraphStyle({
3474              start: -10,
3475              end: -10,
3476              style: {
3477                leadingMargin: margin
3478              }
3479            })
3480          })
3481        }
3482      }.borderWidth(1).borderColor(Color.Red)
3483    }
3484  }
3485}
3486```
3487![UpdateParagraphAndTypingStyle](figures/richEditorUpdateParagraphAndTypingStyle.gif)
3488
3489### 示例8(设置文本字重与阴影)
3490通过[updateParagraphStyle](#updateparagraphstyle11)接口设置文本字重与阴影。
3491
3492``` ts
3493@Entry
3494@Component
3495struct Index {
3496  controller: RichEditorController = new RichEditorController();
3497  options: RichEditorOptions = { controller: this.controller };
3498  private start: number = -1;
3499  private end: number = -1;
3500  @State message: string = "[-1, -1]"
3501  @State content: string = ""
3502  @State textShadows : Array<ShadowOptions> = [
3503    { radius: 10, color: Color.Red, offsetX: 10, offsetY: 0 },
3504    { radius: 10, color: Color.Black, offsetX: 20, offsetY: 0 },
3505    { radius: 10, color: Color.Brown, offsetX: 30, offsetY: 0 },
3506    { radius: 10, color: Color.Green, offsetX: 40, offsetY: 0 },
3507    { radius: 10, color: Color.Yellow, offsetX: 100, offsetY: 0 }
3508  ];
3509
3510  build() {
3511    Column() {
3512      Column() {
3513        Text("selection range:").width("100%")
3514        Text() {
3515          Span(this.message)
3516        }.width("100%")
3517        Text("selection content:").width("100%")
3518        Text() {
3519          Span(this.content)
3520        }.width("100%")
3521      }
3522      .borderWidth(1)
3523      .borderColor(Color.Red)
3524      .width("100%")
3525      .height("20%")
3526      Row() {
3527        Button("更新样式: 加粗 & 文本阴影").onClick(() => {
3528          this.controller.updateSpanStyle({
3529            start: this.start,
3530            end: this.end,
3531            textStyle:
3532            {
3533              fontWeight: FontWeight.Bolder,
3534              textShadow: this.textShadows
3535            }
3536          })
3537        })
3538      }
3539      .borderWidth(1)
3540      .borderColor(Color.Red)
3541      .width("100%")
3542      .height("10%")
3543      Column() {
3544        RichEditor(this.options)
3545          .onReady(() => {
3546            this.controller.addTextSpan("0123456789",
3547              {
3548                style:
3549                {
3550                  fontColor: Color.Orange,
3551                  fontSize: 30,
3552                  textShadow: { radius: 10, color: Color.Blue, offsetX: 10, offsetY: 0 }
3553                }
3554              })
3555          })
3556          .borderWidth(1)
3557          .borderColor(Color.Green)
3558          .width("100%")
3559          .height("30%")
3560      }
3561      .borderWidth(1)
3562      .borderColor(Color.Red)
3563      .width("100%")
3564      .height("70%")
3565    }
3566  }
3567}
3568```
3569
3570![TextshadowExample](figures/rich_editor_textshadow.gif)
3571
3572### 示例9(添加用户自定义布局Span)
3573通过[addBuilderSpan](#addbuilderspan11)接口添加用户自定义布局Span。
3574
3575``` ts
3576@Builder
3577function placeholderBuilder2() {
3578  Row({ space: 2 }) {
3579    // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
3580    Image($r('app.media.startIcon')).width(24).height(24).margin({ left: -5 })
3581    Text('okokokok').fontSize(10)
3582  }.width('20%').height(50).padding(10).backgroundColor(Color.Red)
3583}
3584
3585// xxx.ets
3586@Entry
3587@Component
3588struct Index {
3589  controller: RichEditorController = new RichEditorController();
3590  option: RichEditorOptions = { controller: this.controller };
3591  private start: number = 2;
3592  private end: number = 4;
3593  @State message: string = "[-1, -1]";
3594  @State content: string = "";
3595  private my_offset: number | undefined = undefined;
3596  private my_builder: CustomBuilder = undefined;
3597  @BuilderParam my_builder2:() => void = placeholderBuilder2;
3598
3599  @Builder
3600  placeholderBuilder() {
3601    Row({ space: 2 }) {
3602      // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
3603      Image($r('app.media.startIcon')).width(24).height(24).margin({ left: -5 })
3604      Text('Custom Popup').fontSize(10)
3605    }.width(100).height(50).padding(5)
3606  }
3607
3608  @Builder
3609  placeholderBuilder3() {
3610    Text("hello").padding('20').borderWidth(1).width('100%')
3611  }
3612
3613  @Builder
3614  placeholderBuilder4() {
3615    Column() {
3616      Column({ space: 5 }) {
3617        Text('direction:Row').fontSize(9).fontColor(0xCCCCCC).width('90%')
3618        Flex({ direction: FlexDirection.Row }) { // 子组件在容器主抽上行布局
3619          Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
3620          Text('1').width('20%').height(50).backgroundColor(0xD2B48C)
3621          Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
3622          Text('1').width('20%').height(50).backgroundColor(0xD2B48C)
3623        }
3624        .height(70)
3625        .width('90%')
3626        .padding(10)
3627        .backgroundColor(0xAFEEEE)
3628
3629        Text('direction:RowReverse').fontSize(9).fontColor(0xCCCCCC).width('90%')
3630        Flex({ direction: FlexDirection.RowReverse }) { // 子组件在容器主抽上反向行布局
3631          Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
3632          Text('1').width('20%').height(50).backgroundColor(0xD2B48C)
3633          Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
3634          Text('1').width('20%').height(50).backgroundColor(0xD2B48C)
3635        }
3636        .height(70)
3637        .width('90%')
3638        .padding(10)
3639        .backgroundColor(0xAFEEEE)
3640
3641        Text('direction:Column').fontSize(9).fontColor(0xCCCCCC).width('90%')
3642        Flex({ direction: FlexDirection.Column }) { // 子组件在容器主抽上列布局
3643          Text('1').width('20%').height(40).backgroundColor(0xF5DEB3)
3644          Text('1').width('20%').height(40).backgroundColor(0xD2B48C)
3645          Text('1').width('20%').height(40).backgroundColor(0xF5DEB3)
3646          Text('1').width('20%').height(40).backgroundColor(0xD2B48C)
3647        }
3648        .height(160)
3649        .width('90%')
3650        .padding(10)
3651        .backgroundColor(0xAFEEEE)
3652
3653        Text('direction:ColumnReverse').fontSize(9).fontColor(0xCCCCCC).width('90%')
3654        Flex({ direction: FlexDirection.ColumnReverse }) { // 子组件在容器主抽上反向列布局
3655          Text('1').width('20%').height(40).backgroundColor(0xF5DEB3)
3656          Text('1').width('20%').height(40).backgroundColor(0xD2B48C)
3657          Text('1').width('20%').height(40).backgroundColor(0xF5DEB3)
3658          Text('1').width('20%').height(40).backgroundColor(0xD2B48C)
3659        }
3660        .height(160)
3661        .width('90%')
3662        .padding(10)
3663        .backgroundColor(0xAFEEEE)
3664      }.width('100%').margin({ top: 5 })
3665    }.width('100%')
3666  }
3667
3668  @Builder
3669  MyMenu() {
3670    Menu() {
3671      // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
3672      MenuItem({ startIcon: $r('app.media.startIcon'), content: "菜单选项1" })
3673      MenuItem({ startIcon: $r('app.media.startIcon'), content: "菜单选项2" })
3674        .enabled(false)
3675    }
3676  }
3677
3678  build() {
3679    Column() {
3680      Column() {
3681        Text("selection range:").width("100%")
3682        Text() {
3683          Span(this.message)
3684        }.width("100%")
3685
3686        Text("selection content:").width("100%")
3687        Text() {
3688          Span(this.content)
3689        }.width("100%")
3690      }
3691      .borderWidth(1)
3692      .borderColor(Color.Red)
3693      .width("100%")
3694      .height("20%")
3695
3696      Row() {
3697        Button("获取选择内容 getSpans").onClick(() => {
3698          console.info('getSpans='+JSON.stringify(this.controller.getSpans({ start:1, end:5 })));
3699          console.info('getParagraphs='+JSON.stringify(this.controller.getParagraphs({ start:1, end:5 })));
3700          this.content = "";
3701          this.controller.getSpans({
3702            start: this.start,
3703            end: this.end
3704          }).forEach(item => {
3705            if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
3706              if ((item as RichEditorImageSpanResult).valueResourceStr == "") {
3707                console.info("builder span index " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range : " + (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " +
3708                  (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + (item as RichEditorImageSpanResult).imageStyle[0] + ", " + (item as RichEditorImageSpanResult).imageStyle[1])
3709              } else {
3710                console.info("image span " + (item as RichEditorImageSpanResult).valueResourceStr + ", index : " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range: " +
3711                  (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " +
3712                  (item as RichEditorImageSpanResult).imageStyle.size[0] + ", " + (item as RichEditorImageSpanResult).imageStyle.size[1])
3713              }
3714            } else {
3715              this.content += (item as RichEditorTextSpanResult).value;
3716              this.content += "\n";
3717              console.info("text span: " + (item as RichEditorTextSpanResult).value);
3718            }
3719          })
3720        })
3721        Button("获取选择内容 getSelection").onClick(() => {
3722          this.content = "";
3723          let select = this.controller.getSelection();
3724          console.info("selection start " + select.selection[0] + " end " + select.selection[1]);
3725          select.spans.forEach(item => {
3726            if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
3727              if ((item as RichEditorImageSpanResult).valueResourceStr == "") {
3728                console.info("builder span index " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range : " + (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " +
3729                  (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + (item as RichEditorImageSpanResult).imageStyle[0] + ", " + (item as RichEditorImageSpanResult).imageStyle[1])
3730              } else {
3731                console.info("image span " + (item as RichEditorImageSpanResult).valueResourceStr + ", index : " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range: " +
3732                  (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " +
3733                  (item as RichEditorImageSpanResult).imageStyle.size[0] + ", " + (item as RichEditorImageSpanResult).imageStyle.size[1])
3734              }
3735            } else {
3736              this.content += (item as RichEditorTextSpanResult).value;
3737              this.content += "\n";
3738              console.info("text span: " + (item as RichEditorTextSpanResult).value);
3739            }
3740          })
3741        })
3742        Button("删除选择内容").onClick(() => {
3743          this.controller.deleteSpans({
3744            start: this.start,
3745            end: this.end
3746          })
3747        })
3748      }
3749      .borderWidth(1)
3750      .borderColor(Color.Red)
3751      .width("100%")
3752      .height("10%")
3753
3754      Column() {
3755        RichEditor(this.option)
3756          .onReady(() => {
3757            this.controller.addTextSpan("0123456789",
3758              {
3759                style:
3760                {
3761                  fontColor: Color.Orange,
3762                  fontSize: 30
3763                }
3764              })
3765            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
3766            this.controller.addImageSpan($r('app.media.startIcon'),
3767              {
3768                imageStyle:
3769                {
3770                  size: ["57px", "57px"]
3771                }
3772              })
3773          })
3774          .onSelect((value: RichEditorSelection) => {
3775            this.start = value.selection[0];
3776            this.end = value.selection[1];
3777            this.message = "[" + this.start + ", " + this.end + "]";
3778            console.info("onSelect="+JSON.stringify(value));
3779          })
3780          .aboutToIMEInput((value: RichEditorInsertValue) => {
3781            console.info("---------------------- aboutToIMEInput --------------------");
3782            console.info("aboutToIMEInput="+JSON.stringify(value));
3783            console.info("insertOffset:" + value.insertOffset);
3784            console.info("insertValue:" + value.insertValue);
3785            return true;
3786          })
3787          .onIMEInputComplete((value: RichEditorTextSpanResult) => {
3788            console.info("---------------------- onIMEInputComplete --------------------");
3789            console.info("onIMEInputComplete="+JSON.stringify(value));
3790            console.info("spanIndex:" + value.spanPosition.spanIndex);
3791            console.info("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]");
3792            console.info("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]");
3793            console.info("value:" + value.value);
3794          })
3795          .aboutToDelete((value: RichEditorDeleteValue) => {
3796            value.richEditorDeleteSpans.forEach(item => {
3797              console.info("---------------------- item --------------------");
3798              console.info("spanIndex=" + item.spanPosition.spanIndex);
3799              console.info("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]");
3800              console.info("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]");
3801              if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
3802                if ((item as RichEditorImageSpanResult).valueResourceStr == "") {
3803                  console.info("builder span index " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range : " + (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " +
3804                  (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + (item as RichEditorImageSpanResult).imageStyle[0] + ", " + (item as RichEditorImageSpanResult).imageStyle[1])
3805                } else {
3806                  console.info("image span " + (item as RichEditorImageSpanResult).valueResourceStr + ", index : " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range: " +
3807                  (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " +
3808                  (item as RichEditorImageSpanResult).imageStyle.size[0] + ", " + (item as RichEditorImageSpanResult).imageStyle.size[1])
3809                }
3810              } else {
3811                console.info("delete text: " + (item as RichEditorTextSpanResult).value);
3812              }
3813            })
3814            return true;
3815          })
3816          .borderWidth(1)
3817          .borderColor(Color.Green)
3818          .width("100%")
3819          .height("30%")
3820
3821        Button("add span")
3822          .onClick(() => {
3823            let num = this.controller.addBuilderSpan(this.my_builder, { offset: this.my_offset });
3824            console.info('addBuilderSpan return ' + num);
3825          })
3826        Button("add image")
3827          .onClick(() => {
3828            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
3829            let num = this.controller.addImageSpan($r('app.media.startIcon'), {
3830              imageStyle: {
3831                size: ["50px", "50px"],
3832                verticalAlign: ImageSpanAlignment.BOTTOM,
3833                layoutStyle: {
3834                  borderRadius: undefined,
3835                  margin: undefined
3836                }
3837              }
3838            })
3839            console.info('addImageSpan return' + num);
3840          })
3841        Row() {
3842          Button('builder1').onClick(() => {
3843            this.my_builder = () => {
3844              this.placeholderBuilder()
3845            };
3846          })
3847          Button('builder2').onClick(() => {
3848            this.my_builder = () => {
3849              this.my_builder2()
3850            };
3851          })
3852          Button('builder3').onClick(() => {
3853            this.my_builder = () => {
3854              this.placeholderBuilder3()
3855            };
3856          })
3857          Button('builder4').onClick(() => {
3858            this.my_builder = () => {
3859              this.placeholderBuilder4()
3860            };
3861          })
3862        }
3863      }
3864      .borderWidth(1)
3865      .borderColor(Color.Red)
3866      .width("100%")
3867      .height("70%")
3868    }
3869  }
3870}
3871```
3872![AddBuilderSpanExample](figures/rich_editor_addBuilderSpan.gif)
3873
3874### 示例10(使用和管理组件内的BuilderSpan)
3875通过[addBuilderSpan](#addbuilderspan11)接口添加的自定义布局Span,[getSpans](#getspans)、[onWillChange](#onwillchange12)等API不会返回BuilderSpan内部的信息。开发者需要自行维护BuilderSpan的状态,并且在组件内容发生变化时同步更新。
3876
3877```ts
3878const TAG = 'BuilderSpanDemo';
3879
3880class BuilderObject {
3881  content: string
3882  imageUri?: string
3883  type: string
3884  id?: string
3885
3886  constructor(content: string, type: string, imageUri?: string, id?: string) {
3887    this.content = content
3888    this.imageUri = imageUri
3889    this.type = type
3890    this.id = id
3891  }
3892}
3893
3894@Entry
3895@Component
3896struct Index {
3897  controller: RichEditorController = new RichEditorController()
3898  option: RichEditorOptions = { controller: this.controller }
3899  @State content: string = "";
3900  @State start: number = 0;
3901  @State end: number = 0;
3902  private customBuilder: CustomBuilder = undefined;
3903  private builderArray: BuilderObject[] = [];
3904  private indicesToRemove: number[] = [];
3905  private builderId: number = 0;
3906
3907  @Builder
3908  imageTextBuilder(builder: BuilderObject) {
3909    Row({ space: 2 }) {
3910      Image($r(builder.imageUri)).width(24).height(24).margin({ left: -5 })
3911      Text(builder.content).fontSize(10)
3912    }.width(110).height(50).padding(5)
3913  }
3914
3915  @Builder
3916  chipBuilder(builder: BuilderObject) {
3917    Row() {
3918      Text(builder.content)
3919        .fontSize(14)
3920        .fontColor(Color.Black)
3921        .fontFamily('HarmonyHeiTi')
3922        .margin({ right: 4 })
3923
3924      SymbolGlyph($r('sys.symbol.xmark'))
3925        .width(16)
3926        .height(16)
3927        .id(builder.id)
3928        .onClick((event: ClickEvent) => {
3929          this.deleteChipBuilder(event.target.id)
3930        })
3931    }
3932    .width('auto')
3933    .height(28)
3934    .backgroundColor(Color.Gray)
3935    .borderRadius(10)
3936    .padding({
3937      top: 4,
3938      bottom: 4,
3939      left: 12,
3940      right: 12
3941    })
3942  }
3943
3944  private deleteChipBuilder(builderId?: string) {
3945    if (builderId == null || builderId == "") {
3946      console.info(TAG, "delete chipBuilder error");
3947      return
3948    }
3949    let deleteRange: number[] = this.getTargetBuilderSpanRange(builderId)
3950    if (deleteRange.length == 0) {
3951      console.error(TAG, "getTargetBuilderSpanRange failed" + builderId);
3952      return
3953    }
3954    this.builderArray = this.builderArray.filter(item => item.id !== builderId);
3955    this.controller.deleteSpans({ start: deleteRange[0], end: deleteRange[1] });
3956    console.info(TAG, `deleteChipBuilder start = ${deleteRange[0]}, end = ${deleteRange[1]}`);
3957    console.info(TAG, `deleteChipBuilder builderArray + ${this.builderArray.length}`);
3958  }
3959
3960  private getTargetBuilderSpanRange(builderId: string): number[] {
3961    let allSpans = this.controller.getSpans();
3962    let result: number[] = [];
3963    let chitBuilderIndex = 0;
3964    for (let spanIndex = 0; spanIndex < allSpans.length; spanIndex++) {
3965      if (!this.isBuilderSpanResult(allSpans[spanIndex])) {
3966        continue;
3967      }
3968      if (this.builderArray.length <= chitBuilderIndex) {
3969        break;
3970      }
3971      if (this.builderArray[chitBuilderIndex].id === builderId) {
3972        result = allSpans[spanIndex].spanPosition.spanRange;
3973        break;
3974      }
3975      chitBuilderIndex++;
3976    }
3977    return result;
3978  }
3979
3980  private isTextSpanResult(item: RichEditorImageSpanResult | RichEditorTextSpanResult): boolean {
3981    return typeof (item as RichEditorImageSpanResult)['imageStyle'] == 'undefined';
3982  }
3983
3984  private isBuilderSpanResult(item: RichEditorImageSpanResult | RichEditorTextSpanResult): boolean {
3985    return typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined'
3986      && ((item as RichEditorImageSpanResult).valueResourceStr == " "
3987        || (item as RichEditorImageSpanResult).valueResourceStr == "");
3988  }
3989
3990  build() {
3991    Column() {
3992      Scroll() {
3993        Column() {
3994          Text("Builder Info:").width("100%")
3995          Text() {
3996            Span(this.content)
3997          }.width("100%")
3998        }
3999      }
4000      .borderWidth(1)
4001      .borderColor(Color.Red)
4002      .width("100%")
4003      .height("20%")
4004
4005      // 添加Builder时,记录builder的相对顺序,以及builder信息
4006      // getSpans接口valueResourceStr == " "或""的Span是builderSpan,并且会按顺序返回builder
4007      // 可以根据上面两点,在查询时还原builder信息
4008      Button("addImageTextBuilder")
4009        .onClick(() => {
4010          let insertOffset = this.controller.getCaretOffset();
4011          // 'app.media.startIcon'需要替换为开发者所需的图像资源文件。
4012          let builder = new BuilderObject('Custom PopUP ' + this.builderId, 'imageTextBuilder', 'app.media.startIcon');
4013          this.customBuilder = () => {
4014            this.imageTextBuilder(builder);
4015          }
4016          let addIndex = this.addBuilderByIndex(insertOffset);
4017          console.info(TAG, "add imageTextBuilder index = " + addIndex);
4018          this.builderArray.splice(addIndex, 0, builder);
4019          this.controller.addBuilderSpan(this.customBuilder, { offset: insertOffset });
4020          this.builderId++;
4021          console.info(TAG, "add imageTextBuilder success");
4022        })
4023      Button("addChipBuilder")
4024        .onClick(() => {
4025          let insertOffset = this.controller.getCaretOffset();
4026          let builder = new BuilderObject('Hello World ' + this.builderId, 'chipBuilder', '',
4027            'chipBuilder' + this.builderId);
4028          this.customBuilder = () => {
4029            this.chipBuilder(builder);
4030          }
4031          let addIndex = this.addBuilderByIndex(insertOffset);
4032          console.info(TAG, "add addChipBuilder index = " + addIndex);
4033          this.builderArray.splice(addIndex, 0, builder);
4034          this.controller.addBuilderSpan(this.customBuilder, { offset: insertOffset });
4035          this.builderId++;
4036          console.info(TAG, "add chipBuilder success");
4037        })
4038
4039      Row() {
4040        Button("getSpans").onClick(() => {
4041          console.info(TAG, "getSpans = " + JSON.stringify(this.controller.getSpans()));
4042          this.content = "";
4043          let allSpans = this.controller.getSpans();
4044          let builderSpanIndex = 0;
4045          allSpans.forEach(item => {
4046            if (this.isTextSpanResult(item)) {
4047              console.info(TAG, "text span value: " + (item as RichEditorTextSpanResult).value);
4048            } else if (this.isBuilderSpanResult(item)) {
4049              let builderOrder = "This is builderSpan " + builderSpanIndex + ":"
4050              console.info(TAG, builderOrder);
4051              this.content += builderOrder + "\n";
4052              let builderResult = (item as RichEditorImageSpanResult);
4053              let builderIndex = "index: " + builderResult.spanPosition.spanIndex
4054                + ", range: " + builderResult.spanPosition.spanRange[0] + ", "
4055                + builderResult.spanPosition.spanRange[1];
4056              console.info(TAG, builderIndex);
4057              this.content += builderIndex + "\n";
4058              if (builderSpanIndex >= this.builderArray.length) {
4059                console.error(TAG, "getSpans error,  builderSpanIndex = " + builderSpanIndex
4060                  + ", builderArray.length = " + this.builderArray.length);
4061                return;
4062              }
4063              let builderInfo = "content: " + this.builderArray[builderSpanIndex].content
4064                + ", image uri: " + this.builderArray[builderSpanIndex].imageUri
4065                + ", id: " + this.builderArray[builderSpanIndex].id + "\n\n";
4066              console.info(TAG, builderInfo);
4067              this.content += builderInfo;
4068              builderSpanIndex++;
4069            } else {
4070              let imageResult = (item as RichEditorImageSpanResult);
4071              console.info(TAG, "image span " + imageResult.valueResourceStr + ", index: " +
4072              imageResult.spanPosition.spanIndex + ", range: " +
4073              imageResult.offsetInSpan[0] + ", " + imageResult.offsetInSpan[1] + ", size: " +
4074              imageResult.imageStyle.size[0] + ", " + imageResult.imageStyle.size[1]);
4075            }
4076          })
4077        })
4078        Button("deleteSelectedSpans")
4079          .onClick(() => {
4080            this.start = this.controller.getSelection().selection[0];
4081            this.end = this.controller.getSelection().selection[1];
4082            if (this.start == this.end) {
4083              return;
4084            }
4085            let allSpans = this.controller.getSpans();
4086            let needRemoveIndex = 0;
4087            for (let i = 0; i < allSpans.length; i++) {
4088              if (!this.isBuilderSpanResult(allSpans[i])) {
4089                continue;
4090              }
4091              let builderIndex = (allSpans[i] as RichEditorImageSpanResult).spanPosition.spanRange[0];
4092              if (builderIndex < this.start || builderIndex >= this.end) {
4093                needRemoveIndex++;
4094                continue;
4095              }
4096              this.indicesToRemove.push(needRemoveIndex);
4097              needRemoveIndex++;
4098            }
4099            console.info(TAG, "deleteSpans indicesToRemove = " + this.indicesToRemove.toString());
4100            this.deleteBuilderByIndices();
4101            console.info(TAG, "deleteSpans builderArray = " + this.builderArray.length);
4102            this.controller.deleteSpans({ start: this.start, end: this.end });
4103          })
4104      }
4105      .borderWidth(1)
4106      .borderColor(Color.Red)
4107      .width("100%")
4108      .height("5%")
4109
4110      Column() {
4111        RichEditor(this.option)
4112          .onReady(() => {
4113            this.controller.addTextSpan("0123456789",
4114              {
4115                style:
4116                {
4117                  fontColor: Color.Orange,
4118                  fontSize: 30
4119                }
4120              })
4121          })
4122          .aboutToDelete((value: RichEditorDeleteValue) => {
4123            console.info(TAG, "aboutToDelete = " + JSON.stringify(value));
4124            let isBuilderAboutToDelete = this.isBuilderAboutToDelete(value);
4125            console.info(TAG, "aboutToDelete isBuilderAboutToDelete = " + isBuilderAboutToDelete);
4126            this.getIndicesToRemove(value, isBuilderAboutToDelete);
4127            console.info(TAG, "indicesToRemove = " + this.indicesToRemove.toString());
4128            this.deleteBuilderByIndices();
4129            console.info(TAG, "builderArray = " + this.builderArray.length);
4130            return true;
4131          })
4132          .borderWidth(1)
4133          .borderColor(Color.Green)
4134          .width("100%")
4135          .height("30%")
4136      }
4137      .margin({ top: 60 })
4138      .borderWidth(1)
4139      .borderColor(Color.Red)
4140      .width("100%")
4141      .height("70%")
4142    }
4143  }
4144
4145  private isBuilderAboutToDelete(value: RichEditorDeleteValue): boolean {
4146    let flag = false;
4147    for (let i = 0; i < value.richEditorDeleteSpans.length; i++) {
4148      if (this.isBuilderSpanResult(value.richEditorDeleteSpans[i])) {
4149        flag = true;
4150        break;
4151      }
4152    }
4153    return flag;
4154  }
4155
4156  private getIndicesToRemove(value: RichEditorDeleteValue, isBuilderAboutToDelete: boolean): void {
4157    if (!isBuilderAboutToDelete) {
4158      return
4159    }
4160    let allSpans = this.controller.getSpans();
4161    for (let i = 0; i < value.richEditorDeleteSpans.length; i++) {
4162      let needRemoveIndex = 0;
4163      let item = value.richEditorDeleteSpans[i];
4164      if (!this.isBuilderSpanResult(item)) {
4165        continue;
4166      }
4167      let aboutToDeleteBuilderIndex = (item as RichEditorImageSpanResult).spanPosition.spanIndex
4168      for (let j = 0; j < allSpans.length; j++) {
4169        if (!this.isBuilderSpanResult(allSpans[j])) {
4170          continue;
4171        }
4172        let builderIndex = (allSpans[j] as RichEditorImageSpanResult).spanPosition.spanIndex
4173        if (builderIndex == aboutToDeleteBuilderIndex) {
4174          this.indicesToRemove.push(needRemoveIndex)
4175          break;
4176        }
4177        needRemoveIndex++;
4178      }
4179    }
4180  }
4181
4182  private deleteBuilderByIndices(): void {
4183    let indicesSet: Set<number> = new Set(this.indicesToRemove);
4184    let newLength = 0;
4185    for (let i = 0; i < this.builderArray.length; i++) {
4186      if (!indicesSet.has(i)) {
4187        this.builderArray[newLength] = this.builderArray[i];
4188        newLength++;
4189      }
4190    }
4191    this.builderArray.length = newLength;
4192    this.indicesToRemove.length = 0;
4193  }
4194
4195  private addBuilderByIndex(insertOffset: number): number {
4196    if (insertOffset == 0 || this.builderArray.length == 0) {
4197      return 0;
4198    }
4199    let allSpans = this.controller.getSpans();
4200    let addIndex = 0;
4201    for (let i = 0; i < allSpans.length; i++) {
4202      if (!this.isBuilderSpanResult(allSpans[i])) {
4203        continue;
4204      }
4205      let builderIndex = (allSpans[i] as RichEditorImageSpanResult).spanPosition.spanRange[0];
4206      if (builderIndex < insertOffset) {
4207        addIndex++;
4208        continue;
4209      }
4210      break;
4211    }
4212    return addIndex;
4213  }
4214}
4215```
4216![BuilderSpanManagerExample](figures/rich_editor_builderSpanManager.gif)
4217
4218### 示例11(设置文本识别配置)
4219设置[enableDataDetector](#enabledatadetector11)为true时,通过[dataDetectorConfig](#datadetectorconfig11)接口设置文本识别配置。
4220
4221```ts
4222@Entry
4223@Component
4224struct TextExample7 {
4225  controller: RichEditorController = new RichEditorController();
4226  options: RichEditorOptions = { controller: this.controller };
4227  @State phoneNumber: string = '(86) (755) ********';
4228  @State url: string = 'www.********.com';
4229  @State email: string = '***@example.com';
4230  @State address: string = 'XX省XX市XX区XXXX';
4231  @State enableDataDetector: boolean = true;
4232  @State enablePreviewText: boolean = false;
4233  @State types: TextDataDetectorType[] = [];
4234
4235  build() {
4236    Row() {
4237      Column() {
4238        RichEditor(this.options)
4239          .onReady(() => {
4240            this.controller.addTextSpan('电话号码:' + this.phoneNumber + '\n',
4241              {
4242                style:
4243                {
4244                  fontSize: 30
4245                }
4246              })
4247            this.controller.addTextSpan('链接:' + this.url + '\n',
4248              {
4249                style:
4250                {
4251                  fontSize: 30
4252                }
4253              })
4254            this.controller.addTextSpan('邮箱:' + this.email + '\n',
4255              {
4256                style:
4257                {
4258                  fontSize: 30
4259                }
4260              })
4261            this.controller.addTextSpan('地址:' + this.address,
4262              {
4263                style:
4264                {
4265                  fontSize: 30
4266                }
4267              })
4268          })
4269          .copyOptions(CopyOptions.InApp)
4270          .enableDataDetector(this.enableDataDetector)
4271          .dataDetectorConfig({types : this.types, onDetectResultUpdate: (result: string)=>{}})
4272          .enablePreviewText(this.enablePreviewText)
4273          .borderWidth(1)
4274          .padding(10)
4275          .width('100%')
4276      }
4277      .width('100%')
4278    }
4279  }
4280}
4281```
4282### 示例12(设置光标、手柄和底板颜色)
4283通过[caretColor](#caretcolor12)属性设置输入框光标、手柄颜色,通过[selectedBackgroundColor](#selectedbackgroundcolor12)属性设置文本选中底板颜色。
4284
4285``` ts
4286@Entry
4287@Component
4288struct RichEditorDemo {
4289  @State color: Color = Color.Black;
4290  controller: RichEditorController = new RichEditorController();
4291
4292  build() {
4293    Column() {
4294      Row() {
4295        Button("改为红色").onClick(() => {
4296          this.color = Color.Red;
4297        })
4298      }.margin({ top: 50 })
4299
4300      RichEditor({ controller: this.controller })
4301        .onReady(() => {
4302          this.controller.addTextSpan('通过caretColor和selectedBackgroundColor属性设置光标和选中背景色');
4303        })
4304        .width("100%")
4305        .border({ width: 1, radius: 5 })
4306        .key('RichEditor')
4307        .caretColor(this.color)//光标颜色
4308        .selectedBackgroundColor(this.color)//选中背景色
4309        .margin({ top: 50 })
4310    }
4311    .width('100%')
4312  }
4313}
4314```
4315![SetCaretAndSelectedBackgroundColorExample](figures/rich_editor_caret_color.gif)
4316
4317### 示例13(设置行高和字符间距)
4318通过[updateSpanStyle](#updatespanstyle)接口配置文本行高([lineHeight](#richeditortextstyle))和字符间距([letterSpacing](#richeditortextstyle))。
4319
4320```ts
4321@Entry
4322@Component
4323struct RichEditorDemo03 {
4324  controller: RichEditorController = new RichEditorController();
4325  options: RichEditorOptions = { controller: this.controller };
4326  @State start: number = -1;
4327  @State end: number = -1;
4328  @State LH:number = 50;
4329  @State LS:number = 20;
4330
4331  build() {
4332    Column() {
4333      Scroll(){
4334        Column(){
4335          Row() {
4336            Button("行高++").onClick(()=>{
4337              this.LH = this.LH + 5;
4338              this.controller.updateSpanStyle({
4339                start: this.start,
4340                end: this.end,
4341                textStyle:
4342                {
4343                  lineHeight: this.LH
4344                }
4345              })
4346            })
4347            Button("行高--").onClick(()=>{
4348              this.LH = this.LH - 5;
4349              this.controller.updateSpanStyle({
4350                start: this.start,
4351                end: this.end,
4352                textStyle:
4353                {
4354                  lineHeight: this.LH
4355                }
4356              })
4357            })
4358            Button("字符间距++").onClick(()=>{
4359              this.LS = this.LS + 5
4360              this.controller.updateSpanStyle({
4361                start: this.start,
4362                end: this.end,
4363                textStyle:
4364                {
4365                  letterSpacing: this.LS
4366                }
4367              })
4368            })
4369            Button("字符间距--").onClick(()=>{
4370              this.LS = this.LS - 5
4371              this.controller.updateSpanStyle({
4372                start: this.start,
4373                end: this.end,
4374                textStyle:
4375                {
4376                  letterSpacing: this.LS
4377                }
4378              })
4379            })
4380          }
4381        }
4382      }.borderWidth(1)
4383      .borderColor(Color.Red)
4384      .width("100%")
4385      .height("20%")
4386      .margin({top: 20})
4387
4388      Scroll(){
4389        Column() {
4390          Text("LineHeight:" + this.LH).width("100%")
4391          Text("LetterSpacing:" + this.LS).width("100%")
4392        }
4393      }
4394      .borderWidth(1)
4395      .borderColor(Color.Red)
4396      .width("100%")
4397      .height("20%")
4398      .margin({bottom: 20})
4399
4400      Column() {
4401        RichEditor(this.options).clip(true).padding(10)
4402          .onReady(() => {
4403            this.controller.addTextSpan("012345",
4404              {
4405                style:
4406                {
4407                  fontColor: Color.Orange,
4408                  fontSize: 30,
4409                  lineHeight: this.LH,
4410                  letterSpacing: this.LS
4411                }
4412              })
4413            this.controller.addTextSpan("6789",
4414              {
4415                style:
4416                {
4417                  fontColor: Color.Black,
4418                  fontSize: 30,
4419                  lineHeight: this.LH,
4420                  letterSpacing: this.LS
4421                }
4422              })
4423          })
4424          .borderWidth(1)
4425          .borderColor(Color.Green)
4426          .width(400)
4427          .height(400)
4428      }
4429      .borderWidth(1)
4430      .borderColor(Color.Red)
4431      .width("100%")
4432      .height("60%")
4433    }
4434  }
4435}
4436```
4437![AddBuilderSpanExample](figures/richEditorLineHeightAndLetterSpacing.png)
4438
4439### 示例14(自定义粘贴事件)
4440为组件添加[onPaste](#onpaste11)事件,通过[PasteEvent](#pasteevent11)自定义用户粘贴事件。
4441
4442```ts
4443@Entry
4444@Component
4445struct RichEditorDemo {
4446  controller: RichEditorController = new RichEditorController();
4447  options: RichEditorOptions = { controller: this.controller };
4448
4449  build() {
4450    Column({ space: 2 }) {
4451      RichEditor(this.options)
4452        .onReady(() => {
4453          this.controller.addTextSpan('RichEditor preventDefault')
4454        })
4455        .onPaste((event?: PasteEvent) => {
4456          if (event != undefined && event.preventDefault) {
4457            event.preventDefault();
4458          }
4459        })
4460        .borderWidth(1)
4461        .borderColor(Color.Green)
4462        .width('100%')
4463        .height('40%')
4464    }
4465  }
4466}
4467```
4468![PreventDefaultExample](figures/richEditorPreventDefault.gif)
4469
4470### 示例15(配置文字特性效果)
4471通过[addTextSpan](#addtextspan)接口设置文字特性效果([fontFeature](#richeditortextstyle))。当添加“ss01”特性的FontFeature属性时,数字“0”由原来的椭圆形改变为带有倒圆角形。
4472
4473```ts
4474@Entry
4475@Component
4476struct RichEditorExample {
4477  controller: RichEditorController = new RichEditorController();
4478  options: RichEditorOptions = { controller: this.controller };
4479  @State enableDataDetector: boolean = true;
4480  @State types: TextDataDetectorType[] = [];
4481  build() {
4482    Row() {
4483      Column() {
4484        RichEditor(this.options)
4485          .onReady(() => {
4486            this.controller.addTextSpan('This is ss01 off :' + '0000' + '\n',
4487              {
4488                style:
4489                {
4490                  fontSize: 30
4491                }
4492              })
4493            this.controller.addTextSpan('This is ss01 on :' + '0000' + '\n',
4494              {
4495                style:
4496                {
4497                  fontSize: 30,
4498                  fontFeature: "\"ss01\" 1"
4499                }
4500              })
4501          })
4502          .copyOptions(CopyOptions.InApp)
4503          .enableDataDetector(this.enableDataDetector)
4504          .dataDetectorConfig({types : this.types, onDetectResultUpdate: (result: string)=>{}})
4505          .borderWidth(1)
4506          .padding(10)
4507          .width('100%')
4508      }
4509      .width('100%')
4510      .margin({top:150})
4511    }
4512  }
4513}
4514```
4515![FontFeatureExample](figures/richEditorFontFeature.png)
4516
4517### 示例16(自定义键盘避让)
4518通过[customKeyboard](#customkeyboard)属性绑定自定义键盘,通过参数[KeyboardOptions](#keyboardoptions12)设置自定义键盘是否支持避让功能。
4519
4520```ts
4521@Entry
4522@Component
4523struct RichEditorExample {
4524  controller: RichEditorController = new RichEditorController();
4525  @State height1: string | number = '80%';
4526  @State height2: number = 100;
4527  @State supportAvoidance: boolean = true;
4528
4529  // 自定义键盘组件
4530  @Builder
4531  CustomKeyboardBuilder() {
4532    Column() {
4533      Row() {
4534        Button('增加特表情包').onClick(() => {
4535          this.controller.addTextSpan("\uD83D\uDE0A",
4536            {
4537              style:
4538              {
4539                fontColor: Color.Orange
4540              }
4541            })
4542        })
4543      }
4544
4545      Grid() {
4546        ForEach(['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'], (item: string) => {
4547          GridItem() {
4548            Button(item).width(110).onClick(() => {
4549              this.controller.addTextSpan(item, {
4550                offset: this.controller.getCaretOffset(),
4551                style:
4552                {
4553                  fontColor: Color.Orange,
4554                  fontSize: 30
4555                }
4556              })
4557              this.controller.setCaretOffset(this.controller.getCaretOffset() + item.toString().length)
4558            })
4559          }
4560        })
4561      }.maxCount(3).columnsGap(10).rowsGap(10).padding(5)
4562    }.backgroundColor(Color.Gray)
4563  }
4564
4565  build() {
4566    Column() {
4567      Row() {
4568        Button("20%")
4569          .fontSize(24)
4570          .onClick(() => {
4571            this.height1 = "20%";
4572          })
4573        Button("80%")
4574          .fontSize(24)
4575          .margin({ left: 20 })
4576          .onClick(() => {
4577            this.height1 = "80%";
4578          })
4579      }
4580      .justifyContent(FlexAlign.Center)
4581      .alignItems(VerticalAlign.Bottom)
4582      .height(this.height1)
4583      .width("100%")
4584      .padding({ bottom: 50 })
4585
4586      RichEditor({ controller: this.controller })// 绑定自定义键盘
4587        .customKeyboard(this.CustomKeyboardBuilder(), { supportAvoidance: this.supportAvoidance })
4588        .margin(10)
4589        .border({ width: 1 })
4590        .borderWidth(1)
4591        .borderColor(Color.Red)
4592        .width("100%")
4593    }
4594  }
4595}
4596```
4597![CustomRichEditorType](figures/Custom_Rich_Editor.gif)
4598
4599### 示例17(查看编辑状态)
4600通过[isEditing](#isediting12)接口获取当前富文本的编辑状态。为组件添加[onEditingChange](#oneditingchange12)事件,可通过打印日志,获取当前组件是否在编辑态。
4601
4602```ts
4603@Entry
4604@Component
4605struct RichEditor_onEditingChange {
4606  controller: RichEditorController = new RichEditorController();
4607  @State controllerIsEditing: boolean = false;
4608  @Builder
4609
4610  build() {
4611    Column() {
4612      Row() {
4613        Button("点击查看编辑状态isEditing():").onClick(() => {
4614          this.controllerIsEditing = this.controller.isEditing();
4615        })
4616          .padding(5)
4617        Text('' + this.controllerIsEditing)
4618          .width('100%')
4619          .padding(5)
4620          .fontColor(Color.Orange)
4621          .fontSize(20)
4622      }
4623      RichEditor({ controller: this.controller })
4624        .onEditingChange((isEditing: boolean) => {
4625          console.info("Current Editing Status:" + isEditing);
4626        })
4627        .height(400)
4628        .borderWidth(1)
4629        .borderColor(Color.Red)
4630        .width("100%")
4631    }
4632  }
4633}
4634```
4635
4636![RichEditorOnEditingChange](figures/richEditorOnEditingChange.gif)
4637
4638### 示例18(配置文本变化回调)
4639为组件添加[onWillChange](#onwillchange12)事件,能够在组件执行增删操作前,触发回调。
4640
4641```ts
4642@Entry
4643@Component
4644struct RichEditorExample {
4645  controller: RichEditorController = new RichEditorController();
4646  build() {
4647    Column() {
4648      RichEditor({ controller: this.controller })
4649        .height(200)
4650        .borderWidth(1)
4651        .borderColor(Color.Red)
4652        .width("100%")
4653        .onReady(() => {
4654          this.controller.addTextSpan('测试文字TestWord', { style: { fontColor: Color.Orange, fontSize: 30 } })
4655          this.controller.updateSpanStyle({
4656            start: -1,
4657            end: -1,
4658            textStyle:
4659            {
4660              fontWeight: FontWeight.Bolder
4661            }
4662          })
4663        })
4664        .onWillChange((value: RichEditorChangeValue) => {
4665          console.info('测试log: onWillChange');
4666          console.info('rangeBefore: ' + JSON.stringify(value.rangeBefore));
4667          console.info('print replacedSpans');
4668          value.replacedSpans.forEach((item: RichEditorTextSpanResult) => {
4669            console.info('spanPosition:' + JSON.stringify(item.spanPosition));
4670            console.info('value:' + item.value);
4671            console.info('textStyle:' + JSON.stringify(item.textStyle));
4672            console.info('offsetInSpan:' + item.offsetInSpan);
4673            console.info('valueResource:' + item.valueResource);
4674            console.info('paragraphStyle:' + JSON.stringify(item.paragraphStyle));
4675          })
4676          console.info('print replacedImageSpans');
4677          value.replacedImageSpans.forEach((item: RichEditorImageSpanResult) => {
4678            console.info('spanPosition:' + JSON.stringify(item.spanPosition));
4679            console.info('valuePixelMap:' + JSON.stringify(item.valuePixelMap));
4680            console.info('valueResourceStr:' + item.valueResourceStr);
4681            console.info('imageStyle:' + JSON.stringify(item.imageStyle));
4682            console.info('offsetInSpan:' + item.offsetInSpan);
4683          })
4684          console.info('print replacedSymbolSpans');
4685          value.replacedSymbolSpans.forEach((item: RichEditorTextSpanResult) => {
4686            console.info('spanPosition:' + JSON.stringify(item.spanPosition));
4687            console.info('value:' + item.value);
4688            console.info('offsetInSpan:' + item.offsetInSpan);
4689            console.info('symbolSpanStyle:' + JSON.stringify(item.symbolSpanStyle));
4690            console.info('valueResource:' + item.valueResource);
4691            console.info('paragraphStyle:' + JSON.stringify(item.paragraphStyle));
4692          })
4693          return true;
4694        })
4695        .onDidChange((rangeBefore: TextRange, rangeAfter: TextRange) => {
4696          console.info('测试log: onDidChange');
4697          console.info('rangeBefore:' + JSON.stringify(rangeBefore));
4698          console.info('rangeAfter:' + JSON.stringify(rangeAfter));
4699        })
4700        .onCut((event:CutEvent) => {
4701          event.preventDefault!()
4702          console.info('测试log:onCut');
4703        })
4704        .onCopy((event:CopyEvent) => {
4705          event.preventDefault!()
4706          console.info('测试log:onCopy');
4707        })
4708        .onPaste(()=>{
4709          console.info('测试log:onPaste');
4710        })
4711      Text('测试文字Hello')
4712        .lineHeight(50)
4713        .fontSize(24)
4714        .draggable(true)
4715        .onDragStart(()=>{})
4716      TextInput({text:'测试文字NiHao'})
4717        .draggable(true)
4718        .margin(20)
4719    }
4720  }
4721}
4722```
4723### 示例19(配置输入法enter键功能)
4724通过[enterKeyType](#enterkeytype12)属性设置软键盘输入法回车键类型。
4725
4726```ts
4727@Entry
4728@Component
4729struct SoftKeyboardEnterTypeExample {
4730  controller: RichEditorController = new RichEditorController();
4731
4732    build() {
4733    Column() {
4734      Button("停止编辑").onClick(()=>{
4735        this.controller.stopEditing()
4736      })
4737      RichEditor({ controller: this.controller })
4738        .margin(10)
4739        .border({ width: 1 })
4740        .height(200)
4741        .borderWidth(1)
4742        .borderColor(Color.Red)
4743        .width("100%")
4744        .enterKeyType(EnterKeyType.Search)
4745        .onSubmit((enterKey: EnterKeyType, event: SubmitEvent) => {
4746          console.info("trigger richeditor onsubmit" + enterKey);
4747          this.controller.addTextSpan(" type["+ enterKey +"] triggerred")
4748          event.keepEditableState()
4749        })
4750    }.height("100%").justifyContent(FlexAlign.Center)
4751  }
4752}
4753```
4754
4755![SoftKeyboardEnterType](figures/richeditorentertype.gif)
4756
4757### 示例20(设置段落折行规则)
4758通过[updateParagraphStyle](#updateparagraphstyle11)接口设置折行类型([lineBreakStrategy](#richeditorparagraphstyle11)),通过[getParagraphs](#getparagraphs11)接口获取当前段落的折行类型。
4759
4760```ts
4761@Entry
4762@Component
4763struct LineBreakStrategyExample {
4764  controller: RichEditorController = new RichEditorController();
4765  private spanParagraphs: RichEditorParagraphResult[] = [];
4766  @State lineBreakOptionStr: string[] = ['GREEDY', 'HIGH_QUALITY', 'BALANCED'];
4767  @State attributeValue: string = "";
4768  @State testStr: string = "0123456789,0123456789,0123456789,0123456789,0123456789.";
4769  build() {
4770    Column() {
4771      RichEditor({ controller: this.controller })
4772        .onReady(() => {
4773          this.controller.addTextSpan(this.testStr, {
4774            style: {
4775              fontColor: Color.Black,
4776              fontSize: "32"
4777            },
4778            paragraphStyle: {
4779              textAlign: TextAlign.Start,
4780              lineBreakStrategy: LineBreakStrategy.GREEDY
4781            }
4782          })
4783        })
4784        .width(400)
4785        .height(300)
4786        .margin({bottom:20})
4787        .draggable(false)
4788      Column(){
4789        Text('linebreak属性值为:' + this.attributeValue).fontSize(20).fontColor(Color.Black)
4790      }.margin({bottom: 10})
4791      Column({ space: 10 }) {
4792        Button("设置折行类型GREEDY").onClick(() => {
4793          this.controller.updateParagraphStyle({ start: -1, end: -1,
4794            style: {
4795              lineBreakStrategy: LineBreakStrategy.GREEDY
4796            }
4797          })
4798        })
4799        Button("设置折行类型HIGH_QUALITY").onClick(() => {
4800          this.controller.updateParagraphStyle({ start: -1, end: -1,
4801            style: {
4802              lineBreakStrategy: LineBreakStrategy.HIGH_QUALITY
4803            }
4804          })
4805        })
4806        Button("设置折行类型BALANCED").onClick(() => {
4807          this.controller.updateParagraphStyle({ start: -1, end: -1,
4808            style: {
4809              lineBreakStrategy: LineBreakStrategy.BALANCED
4810            }
4811          })
4812        })
4813        Divider()
4814        Row(){
4815          Button("获取linebreak属性值").onClick(() => {
4816            this.spanParagraphs = this.controller.getParagraphs({ start: -1, end: -1 });
4817            console.info("RichEditor getParagraphs:" + JSON.stringify(this.spanParagraphs));
4818            this.spanParagraphs.forEach(item => {
4819              if(typeof(item as RichEditorParagraphResult)['style'] != 'undefined'){
4820                this.attributeValue = "";
4821                console.info('lineBreakStrategy:'+ JSON.stringify((item as RichEditorParagraphResult)['style']));
4822                this.attributeValue += this.lineBreakOptionStr[Number((item as RichEditorParagraphResult)['style'].lineBreakStrategy)];
4823              }
4824            })
4825          })
4826        }
4827      }
4828    }
4829  }
4830}
4831```
4832
4833![LineBreakStrategy](figures/richEditorLineBreak.gif)
4834
4835### 示例21(属性字符串基本功能)
4836从API version 20开始,该示例中[属性字符串](./ts-universal-styled-string.md)通过[RichEditorStyledStringController](#richeditorstyledstringcontroller12)中的[setStyledString](#setstyledstring12)方法与RichEditor组件绑定。通过[getStyledString](#getstyledstring12)接口获取富文本组件显示的属性字符串。
4837
4838```ts
4839// xxx.ets
4840import { LengthMetrics } from '@kit.ArkUI'
4841
4842@Entry
4843@Component
4844struct Index {
4845  stringLength: number = 0;
4846  @State selection: string = "";
4847  @State content: string = "";
4848  @State range: string = "";
4849  @State replaceString: string = "";
4850  @State rangeBefore: string = "";
4851  @State rangeAfter: string = "";
4852  richEditorStyledString: MutableStyledString = new MutableStyledString("");
4853  textStyle: TextStyle = new TextStyle({
4854    fontWeight: FontWeight.Lighter,
4855    fontFamily: 'HarmonyOS Sans',
4856    fontColor: Color.Green,
4857    fontSize: LengthMetrics.vp(30),
4858    fontStyle: FontStyle.Normal
4859  })
4860  fontStyle1: TextStyle = new TextStyle({ fontColor: Color.Blue });
4861  fontStyle2: TextStyle = new TextStyle({
4862    fontWeight: FontWeight.Bolder,
4863    fontFamily: 'Arial',
4864    fontColor: Color.Orange,
4865    fontSize: LengthMetrics.vp(30),
4866    fontStyle: FontStyle.Italic
4867  })
4868
4869  controller1: RichEditorController = new RichEditorController();
4870  options1: RichEditorOptions = { controller: this.controller1 };
4871  // 创建属性字符串对象
4872  mutableStyledString: MutableStyledString = new MutableStyledString("初始属性字符串",
4873    [{ start: 0, length: 5, styledKey: StyledStringKey.FONT, styledValue: this.fontStyle1 }]);
4874  styledString: StyledString = new StyledString("插入属性字符串",
4875    [{ start: 2, length: 4, styledKey: StyledStringKey.FONT, styledValue: this.fontStyle2 }]);
4876  controller: RichEditorStyledStringController = new RichEditorStyledStringController();
4877  options: RichEditorStyledStringOptions = {controller: this.controller};
4878  // 文本内容变化回调
4879  contentChangedListener: StyledStringChangedListener = {
4880    onWillChange: (value: StyledStringChangeValue) => {
4881      this.range = '[ ' + value.range.start + ' , ' + value.range.end + ' ]';
4882      this.replaceString = value.replacementString.getString();
4883      return true;
4884    },
4885    onDidChange: (rangeBefore, rangeAfter) => {
4886      this.rangeBefore = '[ ' + rangeBefore.start + ' , ' + rangeBefore.end + ' ]';
4887      this.rangeAfter = '[ ' + rangeAfter.start + ' , ' + rangeAfter.end + ' ]';
4888    }
4889  }
4890
4891  build() {
4892    Column({space:6}) {
4893      Column() {
4894        Text("选中区信息")
4895          .fontSize(20)
4896          .width("100%")
4897        Text("selection range: " + this.selection).width("100%")
4898        Text("selection content: " + this.content).width("100%")
4899      }
4900      .width("100%")
4901      .height("10%")
4902
4903      Column() {
4904        Text("onWillChange回调信息")
4905          .fontSize(20)
4906          .width("100%")
4907        Text("range: " + this.range).width("100%")
4908        Text("replacementString: " + this.replaceString).width("100%")
4909        Text("onWillChange回调信息")
4910          .fontSize(20)
4911          .width("100%")
4912        Text("rangeBefore: " + this.rangeBefore).width("100%")
4913        Text("rangeAfter: " + this.rangeAfter).width("100%")
4914      }
4915      .borderWidth(1)
4916      .borderColor(Color.Black)
4917      .width("100%")
4918      .height("20%")
4919
4920      RichEditor(this.options)
4921        .onReady(() => {
4922          // 注册文本变化回调
4923          this.controller.onContentChanged(this.contentChangedListener);
4924          // 设定组件展示的属性字符串
4925          this.controller.setStyledString(this.mutableStyledString);
4926        })
4927        .height("20%")
4928        .width("100%")
4929
4930      RichEditor(this.options1)
4931        .onReady(() => {
4932        this.controller1.addTextSpan("把这些文字转换成属性字符串");
4933      })
4934        .height("10%")
4935        .width("100%")
4936        .borderWidth(1)
4937        .borderColor(Color.Black)
4938
4939        Row({space:2}) {
4940          Button("插入图片")
4941            .stateEffect(true)
4942            .onClick(() => {
4943              // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
4944              let imageStyledString = new MutableStyledString(new ImageAttachment({
4945                resourceValue: $r('app.media.startIcon'),
4946                size: { width: 50, height: 50 },
4947                layoutStyle: { borderRadius: LengthMetrics.vp(10) },
4948                verticalAlign: ImageSpanAlignment.BASELINE,
4949                objectFit: ImageFit.Contain,
4950                syncLoad: true
4951              }));
4952              // 获取组件展示的属性字符串
4953              this.richEditorStyledString = this.controller.getStyledString();
4954              this.richEditorStyledString.appendStyledString(imageStyledString)
4955              // 使插入图片后的属性字符串展示在组件上
4956              this.controller.setStyledString(this.richEditorStyledString)
4957              this.controller.setCaretOffset(this.richEditorStyledString.length)
4958          })
4959          Button("插入文本").onClick(() => {
4960            // 获取组件展示的属性字符串
4961            this.richEditorStyledString = this.controller.getStyledString();
4962            this.richEditorStyledString.appendStyledString(this.styledString)
4963            // 使插入文本后的属性字符串展示在组件上
4964            this.controller.setStyledString(this.richEditorStyledString)
4965            this.controller.setCaretOffset(this.richEditorStyledString.length)
4966          })
4967          Button("删除选中内容").onClick(() => {
4968            // 获取选中范围
4969            let richEditorSelection = this.controller.getSelection();
4970            let start = richEditorSelection.start ? richEditorSelection.start : 0;
4971            let end = richEditorSelection.end ? richEditorSelection.end : 0;
4972            if (start < 0 || end <= start) {
4973              return;
4974            }
4975            // 获取组件展示的属性字符串
4976            this.richEditorStyledString = this.controller.getStyledString();
4977            this.richEditorStyledString.removeString(start, end - start)
4978            // 使删除内容后的属性字符串展示在组件上
4979            this.controller.setStyledString(this.richEditorStyledString)
4980          })
4981        }
4982        Row({space:2}) {
4983          Button("获取选中内容").onClick(() => {
4984            // 获取选中范围
4985            let richEditorSelection = this.controller.getSelection();
4986            let start = richEditorSelection.start ? richEditorSelection.start : 0;
4987            let end = richEditorSelection.end ? richEditorSelection.end : 0;
4988            // 获取组件展示的属性字符串
4989            this.richEditorStyledString = this.controller.getStyledString();
4990            this.selection = '[ ' + start + ' , ' + end + ' ]';
4991            if (start == end) {
4992              this.content = "";
4993            } else {
4994              this.content = this.richEditorStyledString.subStyledString(start, end - start).getString();
4995            }
4996          })
4997          Button("更新选中样式").onClick(() => {
4998            // 获取选中范围
4999            let richEditorSelection = this.controller.getSelection();
5000            let start = richEditorSelection.start ? richEditorSelection.start : 0;
5001            let end = richEditorSelection.end ? richEditorSelection.end : 0;
5002            if (start < 0 || end <= start) {
5003              return;
5004            }
5005            // 获取组件展示的属性字符串
5006            this.richEditorStyledString = this.controller.getStyledString();
5007            this.richEditorStyledString.setStyle({
5008              start: start,
5009              length: end - start,
5010              styledKey: StyledStringKey.FONT,
5011              styledValue: this.textStyle
5012            })
5013            // 使变更样式后的属性字符串展示在组件上
5014            this.controller.setStyledString(this.richEditorStyledString)
5015          })
5016        }
5017        Row({space:2}){
5018          //将属性字符串转换成span信息
5019          Button("调用fromStyledString").onClick(() => {
5020            this.controller1.addTextSpan("调用fromStyledString:" +JSON.stringify(this.controller1.fromStyledString(this.mutableStyledString)))
5021          })
5022          //将给定范围的组件内容转换成属性字符串
5023          Button("调用toStyledString").onClick(() => {
5024            this.controller.setStyledString(this.controller1.toStyledString({start:0,end:13}))
5025          })
5026        }
5027    }
5028  }
5029}
5030```
5031
5032![StyledString](figures/StyledString_example20.gif)
5033
5034### 示例22(获取布局信息)
5035通过[getLayoutManager](#getlayoutmanager12)接口获取布局管理器对象,通过[getLineCount](ts-text-common.md#getlinecount)接口获取组件内容或[placeholder](#placeholder12)的总行数,通过[getGlyphPositionAtCoordinate](ts-text-common.md#getglyphpositionatcoordinate)接口获取较为接近给定坐标的字形的位置信息,通过[getLineMetrics](ts-text-common.md#getlinemetrics)接口获取指定行的行信息、文本样式信息、以及字体属性信息。
5036
5037```ts
5038@Entry
5039@Component
5040export struct Index {
5041  @State lineCount: string = ""
5042  @State glyphPositionAtCoordinate: string = ""
5043  @State lineMetrics: string = ""
5044  controller: RichEditorController = new RichEditorController();
5045  @State textStr: string =
5046    'Hello World! 你好,世界!'
5047
5048  build() {
5049    Scroll() {
5050      Column() {
5051        Text('RichEditor组件getLayoutManager接口获取相对于组件的布局信息')
5052          .fontSize(9)
5053          .fontColor(0xCCCCCC)
5054          .width('90%')
5055          .padding(10)
5056        RichEditor({ controller: this.controller })
5057          .borderColor(Color.Red)
5058          .borderWidth(1)
5059          .onReady(() => {
5060            this.controller.addTextSpan(this.textStr)
5061          })
5062          .onAreaChange(() => {
5063            let layoutManager = this.controller.getLayoutManager();
5064            this.lineCount = "LineCount: " + layoutManager.getLineCount();
5065          })
5066
5067        Text('LineCount').fontSize(9).fontColor(0xCCCCCC).width('90%').padding(10)
5068        Text(this.lineCount)
5069
5070        Text('GlyphPositionAtCoordinate').fontSize(9).fontColor(0xCCCCCC).width('90%').padding(10)
5071        Button("相对组件坐标[150,50]字形信息")
5072          .onClick(() => {
5073            let layoutManager: LayoutManager = this.controller.getLayoutManager();
5074            let position = layoutManager.getGlyphPositionAtCoordinate(150, 50);
5075            this.glyphPositionAtCoordinate =
5076            "相对组件坐标[150,50] glyphPositionAtCoordinate position: " + position.position + " affinity: " +
5077            position.affinity;
5078          })
5079          .margin({ bottom: 20, top: 10 })
5080        Text(this.glyphPositionAtCoordinate)
5081
5082        Text('LineMetrics').fontSize(9).fontColor(0xCCCCCC).width('90%').padding(10)
5083        Button("首行行信息、文本样式信息、以及字体属性信息")
5084          .onClick(() => {
5085            let layoutManager: LayoutManager = this.controller.getLayoutManager();
5086            let lineMetrics = layoutManager.getLineMetrics(0);
5087            this.lineMetrics = "lineMetrics is " + JSON.stringify(lineMetrics) + '\n\n';
5088            let runMetrics = lineMetrics.runMetrics;
5089            runMetrics.forEach((value, key) => {
5090              this.lineMetrics += "runMetrics key is " + key + " " + JSON.stringify(value) + "\n\n";
5091            });
5092          })
5093          .margin({ bottom: 20, top: 10 })
5094        Text(this.lineMetrics)
5095      }
5096      .margin({ top: 100, left: 8, right: 8 })
5097    }
5098  }
5099}
5100```
5101
5102![LayoutManager](figures/getLayoutManager.gif)
5103
5104### 示例23(设置系统默认菜单扩展项)
5105从API version 20开始,该示例通过[editMenuOptions](#editmenuoptions12)属性设置系统默认菜单的扩展项,允许配置扩展项的文本内容、图标和回调方法。
5106
5107```ts
5108// xxx.ets
5109@Entry
5110@Component
5111struct RichEditorExample {
5112  controller: RichEditorController = new RichEditorController();
5113  options: RichEditorOptions = { controller: this.controller };
5114  @State endIndex: number | undefined = 0;
5115  onCreateMenu = (menuItems: Array<TextMenuItem>) => {
5116    const idsToFilter: TextMenuItemId[] = [
5117      TextMenuItemId.TRANSLATE,
5118      TextMenuItemId.SHARE,
5119      TextMenuItemId.SEARCH,
5120      TextMenuItemId.AI_WRITER
5121    ]
5122    const items = menuItems.filter(item => !idsToFilter.some(id => id.equals(item.id)))
5123    // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
5124    let item1: TextMenuItem = {
5125      content: 'create1',
5126      icon: $r('app.media.startIcon'),
5127      id: TextMenuItemId.of('create1'),
5128    };
5129    let item2: TextMenuItem = {
5130      content: 'create2',
5131      id: TextMenuItemId.of('create2'),
5132      icon: $r('app.media.startIcon'),
5133    };
5134    items.push(item1);
5135    items.unshift(item2);
5136    return items;
5137  }
5138  onMenuItemClick = (menuItem: TextMenuItem, textRange: TextRange) => {
5139    if (menuItem.id.equals(TextMenuItemId.of("create2"))) {
5140      console.info("拦截 id: create2 start:" + textRange.start + "; end:" + textRange.end);
5141      return true;
5142    }
5143    if (menuItem.id.equals(TextMenuItemId.of("prepare1"))) {
5144      console.info("拦截 id: prepare1 start:" + textRange.start + "; end:" + textRange.end);
5145      return true;
5146    }
5147    if (menuItem.id.equals(TextMenuItemId.COPY)) {
5148      console.info("拦截 COPY start:" + textRange.start + "; end:" + textRange.end);
5149      return true;
5150    }
5151    if (menuItem.id.equals(TextMenuItemId.SELECT_ALL)) {
5152      console.info("不拦截 SELECT_ALL start:" + textRange.start + "; end:" + textRange.end);
5153      return false;
5154    }
5155    return false;
5156  }
5157  // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
5158  onPrepareMenu = (menuItems: Array<TextMenuItem>) => {
5159    let item1: TextMenuItem = {
5160      content: 'prepare1_' + this.endIndex,
5161      icon: $r('app.media.startIcon'),
5162      id: TextMenuItemId.of('prepare1'),
5163    };
5164    menuItems.unshift(item1);
5165    return menuItems;
5166  }
5167  @State editMenuOptions: EditMenuOptions = {
5168    onCreateMenu: this.onCreateMenu,
5169    onMenuItemClick: this.onMenuItemClick,
5170    onPrepareMenu: this.onPrepareMenu
5171  };
5172
5173  build() {
5174    Column() {
5175      RichEditor(this.options)
5176        .onReady(() => {
5177          this.controller.addTextSpan("RichEditor editMenuOptions")
5178        })
5179        .editMenuOptions(this.editMenuOptions)
5180        .onSelectionChange((range: RichEditorRange) => {
5181          console.info("onSelectionChange, (" + range.start + "," + range.end + ")");
5182          this.endIndex = range.end
5183        })
5184        .height(50)
5185        .margin({ top: 100 })
5186        .borderWidth(1)
5187        .borderColor(Color.Red)
5188    }
5189    .width("90%")
5190    .margin("5%")
5191  }
5192}
5193```
5194
5195![RichEditorEditMenuOptions](figures/richEditorEditMenuOptions.gif)
5196
5197### 示例24(组件部分常用属性)
5198从API version 18开始,该示例通过[barState](#barstate13)属性设置组件滚动条的显示模式。通过[enableKeyboardOnFocus](#enablekeyboardonfocus12)属性设置组件通过点击以外的方式获焦时,是否主动拉起软键盘。通过[enableHapticFeedback](#enablehapticfeedback13)属性设置组件是否支持触感反馈。通过[getPreviewText](#getpreviewtext12)接口获取组件预上屏信息。通过[stopBackPress](#stopbackpress18)属性设置是否阻止返回键向其它组件或应用侧传递。
5199
5200```ts
5201// xxx.ets
5202import { JSON } from '@kit.ArkTS';
5203
5204@Entry
5205@Component
5206struct RichEditor_example {
5207  controller: RichEditorController = new RichEditorController();
5208  options: RichEditorOptions = { controller: this.controller };
5209
5210  controller1: RichEditorController = new RichEditorController();
5211  options1: RichEditorOptions = { controller: this.controller1 };
5212
5213  @State e: boolean = true;
5214  @State bs_num: number = 0;
5215  @State bs: (BarState | undefined)[] = [BarState.Auto, BarState.On, BarState.Off, undefined];
5216  @State bs_string: string[] = ["Auto", "On", "Off", "undefined"];
5217
5218  build() {
5219    Column({space: 3}) {
5220      RichEditor(this.options)
5221        .onReady(() => {
5222          this.controller.addTextSpan('文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本', {
5223            style: {
5224              fontColor: Color.Black,
5225              fontSize: 15
5226            }
5227          })
5228        })
5229        .onDidIMEInput((value: TextRange) => {
5230          this.controller1.addTextSpan("\n" + "触发了onDidIMEInput回调,输入法本次输入内容范围为:(" + value.start + "," + value.end + ")", {
5231            style: {
5232              fontColor: Color.Gray,
5233              fontSize: 10
5234            }
5235          })
5236        })
5237        .onSelectionChange((value: RichEditorRange) => {
5238          this.controller1.addTextSpan("\n" + "触发了onSelectionChange回调,起始范围信息为:(" + value.start + "," + value.end + ")", {
5239            style: {
5240              fontColor: Color.Gray,
5241              fontSize: 10
5242            }
5243          })
5244        })
5245        .width(300)
5246        .height(100)
5247        .margin(20)
5248        .barState(this.bs[this.bs_num])
5249        .enableKeyboardOnFocus(this.e)
5250        .enableHapticFeedback(true)
5251        .stopBackPress(false);
5252
5253      RichEditor(this.options1).width(300)
5254
5255      Button('设置barState为:' + this.bs_string[this.bs_num])
5256        .height(30)
5257        .fontSize(13)
5258        .onClick(() => {
5259          this.bs_num++;
5260          if (this.bs_num > (this.bs.length - 1)) {
5261            this.bs_num = 0;
5262          }
5263        })
5264
5265      Button('设置enableKeyboardOnFocus为:' + this.e)
5266        .height(30)
5267        .fontSize(13)
5268        .onClick(() => {
5269          this.e = !this.e;
5270        })
5271
5272      Button('获取预上屏信息')
5273        .height(30)
5274        .fontSize(13)
5275        .onClick(() => {
5276          this.controller1.addTextSpan("\n获取预上屏信息:" + JSON.stringify(this.controller.getPreviewText()))
5277        })
5278    }
5279  }
5280}
5281
5282```
5283
5284![StyledString](figures/example23.gif)
5285
5286### 示例25(获取光标相对组件位置的矩形)
5287从API version 18开始,该示例通过RichEditorBaseController的[getCaretRect](#getcaretrect18)方法来获取当前光标相对于组件位置的Rect。
5288
5289```ts
5290// xxx.ets
5291@Entry
5292@Component
5293struct Index {
5294  controller: RichEditorController = new RichEditorController();
5295  options: RichEditorOptions = { controller: this.controller };
5296  @State caretRect: string = "not found";
5297
5298  build() {
5299    Column() {
5300      Button('get caret rect')
5301        .onClick(() => {
5302          let rectCaret = this.controller.getCaretRect();
5303          if(rectCaret == undefined) {
5304            this.caretRect = 'undefined';
5305          } else {
5306            this.caretRect = 'X: ' + rectCaret.x + '\nY: ' + rectCaret.y
5307              + '\nWidth: ' + rectCaret.width + '\nHeight: ' + rectCaret.height;
5308          }
5309        })
5310        .fontSize(24)
5311        .width("60%")
5312        .height("10%")
5313
5314      Text(this.caretRect)
5315        .margin(12)
5316        .fontSize(24)
5317
5318      RichEditor(this.options)
5319        .onReady(() => {
5320          this.controller.addTextSpan('12345678901234567890', {
5321            style:
5322            {
5323              fontColor: Color.Orange,
5324              fontSize: 50
5325            }
5326          })
5327        })
5328        .borderWidth(1)
5329        .borderColor(Color.Red)
5330        .width("100%")
5331        .height("60%")
5332    }
5333  }
5334}
5335
5336```
5337
5338![StyledString](figures/example24.gif)
5339
5340### 示例26(设置最大行数和最大字符数)
5341从API version 18开始,该示例通过[maxLength](#maxlength18)设置可输入的最大字符数,通过[maxLines](#maxlines18)设置可输入的最大行数。
5342
5343```ts
5344@Entry
5345@Component
5346struct RichEditorExample {
5347  @State text: string = "As the sun begins to set, casting a warm golden hue across the sky," +
5348    "the world seems to slow down and breathe a sigh of relief. The sky is painted with hues of orange, " +
5349    " pink, and lavender, creating a breathtaking tapestry that stretches as far as the eye can see." +
5350    "The air is filled with the sweet scent of blooming flowers, mingling with the earthy aroma of freshly turned soil." +
5351    "it casts a warm," +
5352    "golden hue that spreads like liquid amber across the vast expanse of the sky." +
5353    "The once-blue heavens gradually transform, " +
5354    "now painted in a breathtaking palette of soft oranges, pinks, " +
5355    "and purples, each color blending seamlessly into the next. Wisps of clouds, tinged with fiery edges, " +
5356    "float lazily amidst this celestial canvas," +
5357    "creating a scene so serene and beautiful that it almost seems to pause time itself." +
5358    "As the sun begins to set, casting a warm golden hue across the sky," +
5359    "the world seems to slow down and breathe a sigh of relief. The sky is painted with hues of orange, " +
5360    " pink, and lavender, creating a breathtaking tapestry that stretches as far as the eye can see." +
5361    "The air is filled with the sweet scent of blooming flowers, mingling with the earthy aroma of freshly turned soil." +
5362    "it casts a warm," +
5363    "golden hue that spreads like liquid amber across the vast expanse of the sky." +
5364    "The once-blue heavens gradually transform, ";
5365  @State maxLineList: (number | undefined)[] = [2, 6, undefined];
5366  @State maxLineIndex: number = 0;
5367  @State maxLineStringList: (string)[] = ["2", "6", "undefined"];
5368  richEditorStyledString: MutableStyledString = new MutableStyledString("");
5369  controller1: RichEditorController = new RichEditorController();
5370  controller2: TextInputController = new TextInputController();
5371  controller3: RichEditorController = new RichEditorController();
5372  controller4: RichEditorStyledStringController = new RichEditorStyledStringController();
5373  controller: RichEditorController = new RichEditorController();
5374  option: RichEditorOptions = { controller: this.controller };
5375
5376  build() {
5377    Column() {
5378      Text("当前的maxLength为7 ")
5379        .margin(10)
5380        .fontSize(25)
5381      Row() {
5382        Button("插入占1字符数的图片")
5383          .onClick(() => {
5384            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
5385            this.controller1.addImageSpan($r('app.media.startIcon'),
5386              {
5387                imageStyle:
5388                {
5389                  size: ["57px", "57px"]
5390                }
5391              })
5392          })
5393        Button("插入占2字符数图片")
5394          .onClick(() => {
5395            this.controller1.addSymbolSpan($r("sys.symbol.ohos_trash"),
5396              {
5397                style:
5398                {
5399                  fontSize: 30
5400                }
5401              })
5402          })
5403          .margin({ left: 20 })
5404      }
5405
5406      RichEditor({ controller: this.controller1 })
5407        .width('95%')
5408        .margin(10)
5409        .height(60)
5410        .maxLength(7)
5411        .backgroundColor('rgb(240,250,255)')
5412      Text("当前的maxLine为 " + this.maxLineStringList[this.maxLineIndex]).margin(10)
5413        .fontSize(25)
5414      Button("更改maxLines").onClick(() => {
5415        this.maxLineIndex++;
5416        if (this.maxLineIndex > this.maxLineList.length - 1) {
5417          this.maxLineIndex = 0;
5418        }
5419      })
5420      RichEditor({ controller: this.controller3 })
5421        .onReady(() => {
5422          this.controller3.addTextSpan(this.text,
5423            {
5424              style:
5425              {
5426                fontColor: 'rgb(0,74,175)'
5427              }
5428            })
5429        })
5430        .margin(10)
5431        .width('95%')
5432        .maxLines(this.maxLineList[this.maxLineIndex])
5433        .backgroundColor('rgb(240,250,255)')
5434    }
5435  }
5436}
5437```
5438![StyledString](figures/maxLengthmaxLines.gif)
5439
5440### 示例27(文本设置Url样式)
5441从API version 19开始,该示例通过在addTextSpan和UpdateSpanStyle接口中加入[UrlStyle](#richeditorurlstyle19),来实现文本点击时跳转到指定链接的功能。
5442
5443```ts
5444// xxx.ets
5445
5446@Entry
5447@Component
5448struct RichEditorExample {
5449  controller: RichEditorController = new RichEditorController();
5450  options: RichEditorOptions = { controller: this.controller };
5451  styledStringController: RichEditorStyledStringController = new RichEditorStyledStringController();
5452  styledStringOptions: RichEditorStyledStringOptions = { controller: this.styledStringController };
5453
5454  build() {
5455    Column() {
5456      Row() {
5457        Button("Add Example Url").onClick(() => {
5458          this.controller.addTextSpan("示例网址", {
5459            urlStyle: { url: "https://www.example.com" }
5460          })
5461        })
5462        Button("Clear Url").onClick(() => {
5463          this.controller.updateSpanStyle({
5464            start: 0,
5465            textStyle: {},
5466            urlStyle: { url: "" }
5467          })
5468        })
5469      }
5470
5471      Row() {
5472        RichEditor(this.options)
5473          .height('35%')
5474          .border({ width: 1, color: Color.Blue })
5475      }
5476
5477      Row() {
5478        RichEditor(this.styledStringOptions)
5479          .height('35%')
5480          .border({ width: 1, color: Color.Red })
5481      }
5482    }
5483  }
5484}
5485```
5486
5487### 示例28(开启带样式的撤销还原能力)
5488从API version 20开始,该示例对于不使用属性字符串的富文本组件,可以通过配置[undoStyle](#undostyle20)属性为UndoStyle.KEEP_STYLE,以支持撤销还原时保留原内容的样式。
5489
5490```ts
5491// xxx.ets
5492
5493@Entry
5494@Component
5495struct StyledUndo {
5496  controller: RichEditorController = new RichEditorController();
5497  options: RichEditorOptions = { controller: this.controller };
5498  private start: number = 0;
5499  private end: number = 0;
5500  @State undoStyle: UndoStyle = UndoStyle.KEEP_STYLE;
5501  build() {
5502    Column() {
5503      Column() {
5504        Row({space:2}) {
5505          Button("插入文本").onClick(() => {
5506            this.controller.addTextSpan("插入文本",
5507              {
5508                style:
5509                {
5510                  fontColor: Color.Orange,
5511                  fontSize: 32
5512                }
5513              })
5514          })
5515          Button("插入图片").onClick(() => {
5516            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
5517            this.controller.addImageSpan($r('app.media.startIcon'),
5518              {
5519                imageStyle:
5520                {
5521                  size: ["100px", "100px"]
5522                }
5523              });
5524          })
5525          Button("插入Symbol").onClick(() => {
5526            this.controller.addSymbolSpan($r("sys.symbol.ohos_trash"),
5527              {
5528                style:
5529                {
5530                  fontSize: 32
5531                }
5532              });
5533          })
5534        }
5535        .borderWidth(1)
5536        .borderColor(Color.Red)
5537        .justifyContent(FlexAlign.Center)
5538        .width("100%")
5539        .height("10%")
5540        Row({space:2}) {
5541          Button("更新选中范围样式").onClick(() => {
5542            if (this.start < this.end) {
5543              this.controller.updateSpanStyle({
5544                start: this.start,
5545                end: this.end,
5546                textStyle:
5547                {
5548                  fontColor: Color.Red,
5549                  fontWeight: FontWeight.Bolder
5550                }
5551              });
5552            }
5553          })
5554          Button("删除选中范围内容").onClick(() => {
5555            if (this.start < this.end) {
5556              this.controller.deleteSpans({
5557                start: this.start,
5558                end: this.end
5559              })
5560            }
5561          })
5562        }
5563        .borderWidth(1)
5564        .borderColor(Color.Red)
5565        .justifyContent(FlexAlign.Center)
5566        .width("100%")
5567        .height("10%")
5568        Row({space:2}) {
5569          Button("撤销时不还原样式").onClick(() => {
5570            this.undoStyle = UndoStyle.CLEAR_STYLE;
5571          })
5572          Button("撤销时还原样式").onClick(() => {
5573            this.undoStyle = UndoStyle.KEEP_STYLE;
5574          })
5575        }
5576        .borderWidth(1)
5577        .borderColor(Color.Red)
5578        .justifyContent(FlexAlign.Center)
5579        .width("100%")
5580        .height("10%")
5581      }
5582      Column() {
5583        RichEditor(this.options)
5584          .onReady(()=>{
5585            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
5586            this.controller.addImageSpan($r('app.media.startIcon'),
5587            {
5588              imageStyle:
5589              {
5590                size: ["100px", "100px"]
5591              }
5592            });
5593            this.controller.addTextSpan("初始化图文混排内容",
5594              {
5595                style:
5596                {
5597                  fontColor: Color.Orange,
5598                  fontSize: 32
5599                }
5600              })
5601            this.controller.addSymbolSpan($r("sys.symbol.ohos_trash"),
5602              {
5603                style:
5604                {
5605                  fontSize: 32
5606                }
5607              });
5608          })
5609          .undoStyle(this.undoStyle)
5610          .onSelect((value: RichEditorSelection) => {
5611            this.start = value.selection[0];
5612            this.end = value.selection[1];
5613          })
5614          .borderWidth(1)
5615          .borderColor(Color.Green)
5616          .width("100%")
5617          .height("50%")
5618      }
5619    }
5620  }
5621}
5622```
5623![UndoStyle](figures/richEditorStyledUndo.gif)
5624
5625### 示例29(文本设置预设段落样式)
5626从API version 20开始,该示例通过[setTypingParagraphStyle](#settypingparagraphstyle20)接口设置预设段落样式。
5627
5628```ts
5629@Entry
5630@Component
5631struct RichEditorExample {
5632  controller: RichEditorController = new RichEditorController()
5633  options: RichEditorOptions = { controller: this.controller }
5634  ssController: RichEditorStyledStringController = new RichEditorStyledStringController()
5635  ssOptions: RichEditorStyledStringOptions = { controller: this.ssController }
5636  contentChangedListener: StyledStringChangedListener = {
5637    onWillChange: (value: StyledStringChangeValue) => {
5638      let range = '[ ' + value.range.start + ' , ' + value.range.end + ' ]';
5639      let replaceString = value.replacementString.getString();
5640      console.info('styledString, onWillChange, range=' + range);
5641      console.info('styledString, onWillChange, replaceString=' + replaceString);
5642      let styles: Array<SpanStyle> = []
5643      if (replaceString.length != 0) {
5644        styles = value.replacementString.getStyles(0, replaceString.length, StyledStringKey.PARAGRAPH_STYLE)
5645      }
5646      styles.forEach((style) => {
5647        let value = style.styledValue
5648        let paraStyle: ParagraphStyle = value as ParagraphStyle
5649        if (paraStyle != undefined) {
5650          console.info('styledString, onWillChange, textAlign=' + JSON.stringify(paraStyle.textAlign)
5651            + ', textIndent=' + JSON.stringify(paraStyle.textIndent)
5652            + ', maxLines=' + JSON.stringify(paraStyle.maxLines)
5653            + ', overflow=' + JSON.stringify(paraStyle.overflow)
5654            + ', wordBreak=' + JSON.stringify(paraStyle.wordBreak)
5655            + ', leadingMargin=' + JSON.stringify(paraStyle.leadingMargin)
5656            + ', paragraphSpacing=' + JSON.stringify(paraStyle.paragraphSpacing)
5657          );
5658        }
5659      })
5660      return true;
5661    }
5662  }
5663
5664  build() {
5665    Column() {
5666      Row() {
5667        Text('ParaStyle')
5668        // 设置预设段落样式为居中对齐
5669        Button('setStyle1').onClick(() => {
5670          let paragraphStyle: RichEditorParagraphStyle = {
5671            textAlign: TextAlign.Center
5672          }
5673          this.controller.setTypingParagraphStyle(paragraphStyle)
5674          this.ssController.setTypingParagraphStyle(paragraphStyle)
5675        })
5676        // 设置预设段落样式为左对齐、带有缩进
5677        Button('setStyle2').onClick(() => {
5678          let paragraphStyle: RichEditorParagraphStyle = {
5679            textAlign: TextAlign.Start,
5680            leadingMargin: 80
5681          }
5682          this.controller.setTypingParagraphStyle(paragraphStyle)
5683          this.ssController.setTypingParagraphStyle(paragraphStyle)
5684        })
5685        // 清除预设段落样式
5686        Button('clearParaStyle').onClick(() => {
5687          this.controller.setTypingParagraphStyle(undefined)
5688          this.ssController.setTypingParagraphStyle(undefined)
5689        })
5690      }
5691
5692      Row() {
5693        Column() {
5694          RichEditor(this.options)
5695            .height('25%')
5696            .width('100%')
5697            .border({ width: 1, color: Color.Blue })
5698            .onWillChange((value: RichEditorChangeValue) => {
5699              console.info('controller, onWillChange, rangeBefore=' + JSON.stringify(value.rangeBefore))
5700              value.replacedSpans.forEach((item: RichEditorTextSpanResult) => {
5701                console.info('controller, onWillChange, replacedTextSpans=' + JSON.stringify(item))
5702              })
5703              return true
5704            })
5705          RichEditor(this.ssOptions)
5706            .height('25%')
5707            .width('100%')
5708            .onReady(() => {
5709              this.ssController.onContentChanged(this.contentChangedListener);
5710            })
5711        }
5712      }
5713    }
5714  }
5715}
5716```
5717
5718### 示例30(设置装饰线粗细和多装饰线)
5719从API version 20开始,该示例通过[thicknessScale](ts-universal-styled-string.md#decorationstyle)设置装饰线粗细,通过[enableMultiType](ts-universal-styled-string.md#decorationoptions20)设置多装饰线。
5720
5721```ts
5722import { LengthMetrics } from '@kit.ArkUI';
5723
5724@Entry
5725@Component
5726struct Index {
5727  private controller: RichEditorController = new RichEditorController();
5728  private styledStringController: RichEditorStyledStringController = new RichEditorStyledStringController();
5729
5730  build() {
5731    Column({ space: 20 }) {
5732      RichEditor({ controller: this.controller })
5733        .onReady(() => {
5734          // 预置一段文本
5735          this.controller.addTextSpan('一段预置的文本', {
5736            style: {
5737              fontSize: 25,
5738              decoration: {
5739                type: TextDecorationType.LineThrough,
5740                // 设置装饰线粗细比例为2
5741                thicknessScale: 2
5742              }
5743            }
5744          })
5745        })
5746
5747      // 设置富文本多装饰线
5748      RichEditor({ controller: this.styledStringController })
5749
5750      Button('追加粗细比例为8的文本')
5751        .fontSize(20)
5752        .onClick(() => {
5753          this.controller.addTextSpan('追加的文本', {
5754            style: {
5755              fontSize: 25,
5756              decoration: {
5757                type: TextDecorationType.LineThrough,
5758                // 设置装饰线粗细比例为8
5759                thicknessScale: 8
5760              }
5761            }
5762          })
5763        })
5764
5765      Button('修改全段文本的粗细比例为4')
5766        .fontSize(20)
5767        .onClick(() => {
5768          this.controller.updateSpanStyle({
5769            start: 0,
5770            end: 1000, // 下标超过文本长度时,会更新整段文本
5771            textStyle: {
5772              decoration: {
5773                type: TextDecorationType.LineThrough,
5774                // 设置装饰线粗细比例为4
5775                thicknessScale: 4
5776              }
5777            }
5778          })
5779        })
5780
5781      Button('多装饰线文本')
5782        .fontSize(20)
5783        .onClick(() => {
5784          let mutString: MutableStyledString = new MutableStyledString('设置富文本多装饰线', [
5785            {
5786              start: 0,
5787              length: 9,
5788              styledKey: StyledStringKey.FONT,
5789              styledValue: new TextStyle({ fontSize: LengthMetrics.vp(25) })
5790            },
5791            {
5792              start: 0,
5793              length: 5,
5794              styledKey: StyledStringKey.DECORATION,
5795              styledValue: new DecorationStyle(
5796                {
5797                  type: TextDecorationType.Underline,
5798                },
5799                {
5800                  // 开启多装饰线
5801                  enableMultiType: true
5802                }
5803              )
5804            },
5805            {
5806              start: 2,
5807              length: 4,
5808              styledKey: StyledStringKey.DECORATION,
5809              styledValue: new DecorationStyle(
5810                {
5811                  type: TextDecorationType.LineThrough,
5812                },
5813                {
5814                  // 开启多装饰线
5815                  enableMultiType: true
5816                }
5817              )
5818            },
5819            {
5820              start: 4,
5821              length: 5,
5822              styledKey: StyledStringKey.DECORATION,
5823              styledValue: new DecorationStyle(
5824                {
5825                  type: TextDecorationType.Overline,
5826                },
5827                {
5828                  // 开启多装饰线
5829                  enableMultiType: true
5830                }
5831              )
5832            },
5833          ])
5834          this.styledStringController.setStyledString(mutString);
5835        })
5836    }
5837    .height('100%')
5838    .width('100%')
5839    .justifyContent(FlexAlign.Center)
5840    .alignItems(HorizontalAlign.Center)
5841  }
5842}
5843```
5844![Decoration](figures/decoration_thickness_scale.gif)
5845
5846
5847### 示例31(设置开启中西文自动间距)
5848从API version 20开始,该示例通过[enableAutoSpacing](#enableautospacing20)属性设置中西文自动间距。
5849
5850```ts
5851@Entry
5852@Component
5853struct AutoSpacing {
5854  controller: RichEditorController = new RichEditorController();
5855  options: RichEditorOptions = { controller: this.controller };
5856  @State enableAutoSpace: boolean = false;
5857
5858  build() {
5859    Column() {
5860      Column() {
5861        Row({ space: 2 }) {
5862          Button("插入中西文内容").onClick(() => {
5863            this.controller.addTextSpan("Add文本Span",
5864              {
5865                style:
5866                {
5867                  fontColor: Color.Orange,
5868                  fontSize: 20
5869                }
5870              })
5871          })
5872          Button("插入图片").onClick(() => {
5873            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
5874            this.controller.addImageSpan($r('app.media.startIcon'),
5875              {
5876                imageStyle:
5877                {
5878                  size: ["100px", "100px"]
5879                }
5880              });
5881          })
5882          Button("插入Symbol").onClick(() => {
5883            this.controller.addSymbolSpan($r("sys.symbol.ohos_trash"),
5884              {
5885                style:
5886                {
5887                  fontSize: 32
5888                }
5889              });
5890          })
5891        }
5892        .borderWidth(1)
5893        .borderColor(Color.Red)
5894        .justifyContent(FlexAlign.Center)
5895        .width("100%")
5896        .height("10%")
5897
5898        Row({ space: 2 }) {
5899          Button("开启中西文自动间距").onClick(() => {
5900            this.enableAutoSpace = true;
5901          })
5902          Button("关闭中西文自动间距").onClick(() => {
5903            this.enableAutoSpace = false;
5904          })
5905        }
5906        .borderWidth(1)
5907        .borderColor(Color.Red)
5908        .justifyContent(FlexAlign.Center)
5909        .width("100%")
5910        .height("10%")
5911      }
5912
5913      Column() {
5914        RichEditor(this.options)
5915          .onReady(() => {
5916            // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。
5917            this.controller.addImageSpan($r('app.media.startIcon'),
5918              {
5919                imageStyle:
5920                {
5921                  size: ["100px", "100px"]
5922                }
5923              });
5924            this.controller.addTextSpan("中西文Auto Spacing自动间距",
5925              {
5926                style:
5927                {
5928                  fontColor: Color.Orange,
5929                  fontSize: 20
5930                }
5931              })
5932            this.controller.addSymbolSpan($r("sys.symbol.ohos_trash"),
5933              {
5934                style:
5935                {
5936                  fontSize: 20
5937                }
5938              });
5939          })
5940          .enableAutoSpacing(this.enableAutoSpace)
5941          .borderWidth(1)
5942          .borderColor(Color.Green)
5943          .width("100%")
5944          .height("50%")
5945      }
5946    }
5947  }
5948}
5949```
5950![AutoSpacing](figures/richEditorAutoSpacing.gif)