• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 文本输入 (TextInput/TextArea/Search)
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @kangshihui-->
5<!--Designer: @pssea-->
6<!--Tester: @jiaoaozihao-->
7<!--Adviser: @HelloCrease-->
8
9
10TextInput、TextArea是输入框组件,用于响应用户输入,比如评论区的输入、聊天框的输入、表格的输入等,也可以结合其它组件构建功能页面,例如登录注册页面。具体用法请参考[TextInput](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md)、[TextArea](../reference/apis-arkui/arkui-ts/ts-basic-components-textarea.md)。Search是特殊的输入框组件,称为搜索框,默认样式包含搜索图标。具体用法请参考[Search](../reference/apis-arkui/arkui-ts/ts-basic-components-search.md)。
11
12
13>  **说明:**
14>
15>  仅支持单文本样式,若需实现富文本样式,建议使用[RichEditor](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md)组件。
16
17## 创建输入框
18
19TextInput是单行输入框,TextArea是多行输入框,Search是搜索框。通过以下接口创建这些组件。
20
21```ts
22TextInput(value?:{placeholder?: ResourceStr, text?: ResourceStr, controller?: TextInputController})
23```
24
25```ts
26TextArea(value?:{placeholder?: ResourceStr, text?: ResourceStr, controller?: TextAreaController})
27```
28
29```ts
30Search(options?:{placeholder?: ResourceStr, value?: ResourceStr, controller?: SearchController, icon?: string})
31```
32
33- 单行输入框。
34
35  ```ts
36  TextInput()
37  ```
38
39  ![zh-cn_image_0000001511580844](figures/zh-cn_image_0000001511580844.png)
40
41
42- 多行输入框。
43
44  ```ts
45  TextArea()
46  ```
47
48  ![zh-cn_image_0000001562940481](figures/zh-cn_image_0000001562940481.png)
49
50- 多行输入框文字超出一行时会自动折行。
51
52
53  ```ts
54  TextArea({ text: "我是TextArea我是TextArea我是TextArea我是TextArea" }).width(300)
55  ```
56
57  ![zh-cn_image_0000001511580836](figures/zh-cn_image_0000001511580836.png)
58
59- 搜索框。
60
61  ```ts
62  Search()
63    .searchButton('搜索')
64  ```
65
66  ![zh-ch_image_ui_arkts-common-components-text-input_search_default](figures/zh-ch_image_ui_arkts-common-components-text-input_search_default.png)
67
68## 设置输入框类型
69
70TextInput、TextArea和Search都支持设置输入框类型,通过type属性进行设置,但是各组件的枚举值略有不同。下面以单行输入框为例进行说明。
71
72TextInput有以下类型可选择:Normal基本输入模式、Password密码输入模式、Email邮箱地址输入模式、Number纯数字输入模式、PhoneNumber电话号码输入模式、USER_NAME用户名输入模式、NEW_PASSWORD新密码输入模式、NUMBER_PASSWORD纯数字密码输入模式、<!--Del-->SCREEN_LOCK_PASSWORD锁屏应用密码输入模式、<!--DelEnd-->NUMBER_DECIMAL带小数点的数字输入模式、带URL的输入模式。通过[type](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md#type)属性进行设置:
73
74
75- 基本输入模式(默认类型)。
76
77  ```ts
78  TextInput()
79    .type(InputType.Normal)
80  ```
81
82  ![zh-cn_image_0000001562820765](figures/zh-cn_image_0000001562820765.png)
83
84- 密码输入模式。
85
86  ```ts
87  TextInput()
88    .type(InputType.Password)
89  ```
90
91  ![zh-cn_image_0000001511580840](figures/zh-cn_image_0000001511580840.png)
92
93- 邮箱地址输入模式。
94
95  ```ts
96  TextInput()
97    .type(InputType.Email)
98  ```
99
100  ![text_input_type_email](figures/text_input_type_email.PNG)
101
102- 纯数字输入模式。
103
104  ```ts
105  TextInput()
106    .type(InputType.Number)
107  ```
108
109  ![text_input_type_number](figures/text_input_type_number.PNG)
110
111- 电话号码输入模式。
112
113  ```ts
114  TextInput()
115    .type(InputType.PhoneNumber)
116  ```
117
118  ![text_input_type_phone_number](figures/text_input_type_phone_number.PNG)
119
120- 带小数点的数字输入模式。
121
122  ```ts
123  TextInput()
124    .type(InputType.NUMBER_DECIMAL)
125  ```
126
127  ![text_input_type_number_decimal](figures/text_input_type_number_decimal.PNG)
128
129- 带URL的输入模式。
130
131  ```ts
132  TextInput()
133    .type(InputType.URL)
134  ```
135
136  ![text_input_type_url](figures/text_input_type_url.PNG)
137
138## 自定义样式
139
140- 设置无输入时的提示文本。
141
142
143  ```ts
144  TextInput({ placeholder: '我是提示文本' })
145  ```
146
147  ![zh-cn_image_0000001511900400](figures/zh-cn_image_0000001511900400.png)
148
149
150- 设置输入框当前的文本内容。
151
152  ```ts
153  TextInput({ placeholder: '我是提示文本', text: '我是当前文本内容' })
154  ```
155
156  ![zh-cn_image_0000001562820761](figures/zh-cn_image_0000001562820761.png)
157
158- 添加backgroundColor改变输入框的背景颜色。
159
160  ```ts
161  TextInput({ placeholder: '我是提示文本', text: '我是当前文本内容' })
162    .backgroundColor(Color.Pink)
163  ```
164
165  ![zh-cn_image_0000001511740444](figures/zh-cn_image_0000001511740444.png)
166
167  更丰富的样式可以结合[通用属性](../reference/apis-arkui/arkui-ts/ts-component-general-attributes.md)实现。
168
169
170## 添加事件
171
172文本框主要用于获取用户输入的信息,并将信息处理成数据进行上传,绑定onChange事件可以获取输入框内改变的文本内容,绑定onSubmit事件可以获取回车提交的文本信息,绑定onTextSelectionChange事件可以获取文本选中时手柄的位置信息或者编辑时光标的位置信息等等。用户也可以使用通用事件进行相应的交互操作。
173
174>  **说明:**
175>
176>  在密码模式下,设置showPassword属性时,在onSecurityStateChange回调中,建议增加状态同步,具体详见如下示例。
177>
178> onWillInsert、onDidInsert、onWillDelete、onDidDelete回调仅支持系统输入法的场景。
179>
180> [onWillChange](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md#onwillchange15)的回调时序晚于onWillInsert、onWillDelete,早于onDidInsert、onDidDelete。
181
182```ts
183// xxx.ets
184@Entry
185@Component
186struct Index {
187  @State text: string = '';
188  @State textStr1: string = '';
189  @State textStr2: string = '';
190  @State textStr3: string = '';
191  @State textStr4: string = '';
192  @State textStr5: string = '';
193  @State textStr6: string = '';
194  @State textStr7: string = '';
195  @State textStr8: string = '';
196  @State textStr9: string = '';
197  @State passwordState: boolean = false;
198  controller: TextInputController = new TextInputController();
199
200  build() {
201    Row() {
202      Column() {
203        Text(`${this.textStr1}\n${this.textStr2}\n${this.textStr3}
204        \n${this.textStr4}\n${this.textStr5}\n${this.textStr6}
205        \n${this.textStr7}\n${this.textStr8}\n${this.textStr9}`)
206          .fontSize(20)
207        TextInput({ text: this.text, placeholder: 'input your word...', controller: this.controller })
208          .type(InputType.Password)
209          .showPassword(this.passwordState)
210          .onChange((value: string) => {
211            // 文本内容发生变化时触发该回调
212            console.info('onChange is triggering: ', value);
213            this.textStr1 = `onChange is triggering: ${value}`;
214          })
215          .onSubmit((enterKey: EnterKeyType, event: SubmitEvent) => {
216            // 按下输入法回车键时触发该回调
217            console.info('onSubmit is triggering: ', enterKey, event.text);
218            this.textStr2 = `onSubmit is triggering: ${enterKey} ${event.text}`;
219          })
220          .onTextSelectionChange((selectionStart: number, selectionEnd: number) => {
221            // 文本选择的位置发生变化或编辑状态下光标位置发生变化时,触发该回调
222            console.info('onTextSelectionChange is triggering: ', selectionStart, selectionEnd);
223            this.textStr3 = `onTextSelectionChange is triggering: ${selectionStart} ${selectionEnd}`;
224          })
225          .onSecurityStateChange((isShowPassword: boolean) => {
226            // 密码显隐状态切换时,触发该回调
227            console.info('onSecurityStateChange is triggering: ', isShowPassword);
228            this.passwordState = isShowPassword;
229            this.textStr4 = `onSecurityStateChange is triggering: ${isShowPassword}`;
230          })
231          .onWillInsert((info: InsertValue) => {
232            // 在将要输入时,触发该回调
233            console.info('onWillInsert is triggering: ', info.insertValue, info.insertOffset);
234            this.textStr5 = `onWillInsert is triggering: ${info.insertValue} ${info.insertOffset}`;
235            return true;
236          })
237          .onDidInsert((info: InsertValue) => {
238            // 在输入完成时,触发该回调
239            console.info('onDidInsert is triggering: ', info.insertValue, info.insertOffset);
240            this.textStr6 = `onDidInsert is triggering: ${info.insertValue} ${info.insertOffset}`;
241          })
242          .onWillDelete((info: DeleteValue) => {
243            // 在将要删除时,触发该回调
244            console.info('onWillDelete is triggering: ', info.deleteValue, info.deleteOffset);
245            this.textStr7 = `onWillDelete is triggering: ${info.deleteValue} ${info.deleteOffset}`;
246            return true;
247          })
248          .onDidDelete((info: DeleteValue) => {
249            // 在删除完成时,触发该回调
250            console.info('onDidDelete is triggering: ', info.deleteValue, info.deleteOffset);
251            this.textStr8 = `onDidDelete is triggering: ${info.deleteValue} ${info.deleteOffset}`;
252          })
253          .onFocus(() => {
254            // 绑定通用事件,输入框获焦时触发该回调
255            console.info('onFocus is triggering')
256            this.textStr9 = `onFocus is triggering`;
257          })
258      }.width('100%')
259    }
260    .height('100%')
261  }
262}
263```
264
265![text_input_event](figures/text_input_event.gif)
266
267## 选中菜单
268
269输入框中的文字被选中时会弹出包含剪切、复制、翻译、搜索的菜单。
270
271TextInput:
272```ts
273TextInput({text : '这是一段文本,用来展示选中菜单'})
274```
275![TextInput_select_menu](figures/TexInput_select_menu.jpg)
276
277TextArea:
278```ts
279TextArea({text : '这是一段文本,用来展示选中菜单'})
280```
281![TextArea_select_menu](figures/TextArea_select_menu.jpg)
282
283## 禁用系统服务类菜单
284
285从API version 20开始,支持使用[disableSystemServiceMenuItems](../reference/apis-arkui/arkts-apis-uicontext-textmenucontroller.md#disablesystemservicemenuitems20)方法屏蔽文本选择菜单中的所有系统服务菜单项。
286
287  ```ts
288  import { TextMenuController } from '@kit.ArkUI';
289
290  // xxx.ets
291  @Entry
292  @Component
293  struct Index {
294    aboutToAppear(): void {
295      // 禁用所有系统服务菜单项
296      TextMenuController.disableSystemServiceMenuItems(true)
297    }
298
299    aboutToDisappear(): void {
300      // 页面消失时恢复系统服务菜单项
301      TextMenuController.disableSystemServiceMenuItems(false)
302    }
303
304    build() {
305      Row() {
306        Column() {
307          TextInput({ text: "这是一个TextInput,长按弹出文本选择菜单" })
308            .height(60)
309            .fontStyle(FontStyle.Italic)
310            .fontWeight(FontWeight.Bold)
311            .textAlign(TextAlign.Center)
312            .caretStyle({ width: '4vp' })
313            .editMenuOptions({
314              onCreateMenu: (menuItems: Array<TextMenuItem>) => {
315                // menuItems不包含被屏蔽的系统菜单项
316                return menuItems
317              },
318              onMenuItemClick: (menuItem: TextMenuItem, textRange: TextRange) => {
319                return false
320              }
321            })
322        }.width('100%')
323      }
324      .height('100%')
325    }
326  }
327  ```
328
329  ![TextInput_disable_system_service_menu_items](figures/TextInput_disable_system_service_menu_items.gif)
330
331从API version 20开始,支持使用[disableMenuItems](../reference/apis-arkui/arkts-apis-uicontext-textmenucontroller.md#disablemenuitems20)方法屏蔽文本选择菜单中指定的系统服务菜单项。
332
333  ```ts
334  import { TextMenuController } from '@kit.ArkUI';
335
336  // xxx.ets
337  @Entry
338  @Component
339  struct Index {
340    aboutToAppear(): void {
341      // 禁用搜索和翻译
342      TextMenuController.disableMenuItems([TextMenuItemId.SEARCH, TextMenuItemId.TRANSLATE])
343    }
344
345    aboutToDisappear(): void {
346      // 页面消失时恢复系统服务菜单项
347      TextMenuController.disableMenuItems([])
348    }
349
350    build() {
351      Row() {
352        Column() {
353          TextInput({ text: "这是一个TextInput,长按弹出文本选择菜单" })
354            .height(60)
355            .fontStyle(FontStyle.Italic)
356            .fontWeight(FontWeight.Bold)
357            .textAlign(TextAlign.Center)
358            .caretStyle({ width: '4vp' })
359            .editMenuOptions({
360              onCreateMenu: (menuItems: Array<TextMenuItem>) => {
361                  // menuItems不包含搜索和翻译
362                  return menuItems;
363              },
364              onMenuItemClick: (menuItem: TextMenuItem, textRange: TextRange) => {
365                  return false
366              }
367            })
368        }.width('100%')
369      }
370      .height('100%')
371    }
372  }
373  ```
374
375  ![Text_input_disable_menu_items](figures/Text_input_disable_menu_items.gif)
376
377## 自动填充
378
379输入框可以通过[contentType](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md#contenttype12)属性设置自动填充类型。
380
381支持的类型请参考[ContentType](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md#contenttype12枚举说明)。
382```ts
383TextInput({ placeholder: '输入你的邮箱...' })
384  .width('95%')
385  .height(40)
386  .margin(20)
387  .contentType(ContentType.EMAIL_ADDRESS)
388```
389
390## 设置属性
391
392- 设置省略属性。
393
394  输入框可以通过[ellipsisMode](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md#ellipsismode18)属性设置省略位置。
395
396  ellipsisMode属性需要配合overflow设置为TextOverflow.Ellipsis使用,单独设置ellipsisMode属性不生效。
397
398  ```ts
399  TextInput({ text: '这是一段文本,用来展示省略模式'})
400    .textOverflow(TextOverflow.Ellipsis)
401    .ellipsisMode(EllipsisMode.END)
402    .style(TextInputStyle.Inline)
403    .fontSize(30)
404    .margin(30)
405  ```
406  ![TextInput_ellipsismode](figures/TextInput_ellipsismode.jpg)
407
408- 设置文本描边属性。
409
410  从API version 20开始,输入框可以通过[strokeWidth](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md#strokewidth20)和[strokeColor](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md#strokecolor20)属性设置文本的描边宽度及颜色。
411
412  ```ts
413  TextInput({ text: 'Text with stroke' })
414    .width('100%')
415    .height(60)
416    .borderWidth(1)
417    .fontSize(40)
418    .strokeWidth(LengthMetrics.px(3.0))
419    .strokeColor(Color.Red)
420  ```
421  ![TextInput_stroke](figures/TextInput_stroke.jpg)
422
423## 设置文本行间距
424
425从API version 20开始,支持通过[lineSpacing](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md#linespacing20)设置文本的行间距。如果不配置[LineSpacingOptions](../reference/apis-arkui/arkui-ts/ts-text-common.md#linespacingoptions20对象说明)时,首行上方和尾行下方默认会有行间距。如果onlyBetweenLines设置为true时,行间距仅适用于行与行之间,首行上方无额外行间距。
426
427```ts
428TextArea({
429        text: 'The line spacing of this TextArea is set to 20_px, and the spacing is effective only between the lines.'
430      })
431        .fontSize(22)
432        .lineSpacing(LengthMetrics.px(20), { onlyBetweenLines: true })
433```
434
435![TextInput_line_spacing](figures/TextInput_line_spacing.jpg)
436
437## 键盘避让
438
439键盘抬起后,具有滚动能力的容器组件在横竖屏切换时,才会生效键盘避让,若希望无滚动能力的容器组件也生效键盘避让,建议在组件外嵌套一层具有滚动能力的容器组件,比如[Scroll](../reference/apis-arkui/arkui-ts/ts-container-scroll.md)、[List](../reference/apis-arkui/arkui-ts/ts-container-list.md)、[Grid](../reference/apis-arkui/arkui-ts/ts-container-grid.md)。
440
441```ts
442// xxx.ets
443@Entry
444@Component
445struct Index {
446  placeHolderArr: string[] = ['1', '2', '3', '4', '5', '6', '7'];
447
448  build() {
449    Scroll() {
450      Column() {
451        ForEach(this.placeHolderArr, (placeholder: string) => {
452          TextInput({ placeholder: 'TextInput ' + placeholder })
453            .margin(30)
454        })
455      }
456    }
457    .height('100%')
458    .width('100%')
459  }
460}
461```
462
463![textinputkeyboardavoid](figures/TextInputKeyboardAvoid.gif)
464
465## 光标避让
466
467[keyBoardAvoidMode](../reference/apis-arkui/arkts-apis-uicontext-e.md#keyboardavoidmode11)枚举中的OFFSET和RESIZE在键盘抬起后,不支持二次避让。如果想要支持光标位置在点击或者通过接口设置变化后发生二次避让,可以考虑使用OFFSET_WITH_CARET和RESIZE_CARET替换原有的OFFSET和RESIZE模式。<br>
468对于滚动容器更推荐使用RESIZE_WITH_CARET,非滚动容器应该使用OFFSET_WITH_CARET。
469
470```ts
471// EntryAbility.ets
472import { KeyboardAvoidMode } from '@kit.ArkUI';
473
474// Used in UIAbility
475onWindowStageCreate(windowStage: window.WindowStage) {
476  // Main window is created, set main page for this ability
477  hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
478
479  windowStage.loadContent('pages/Index', (err, data) => {
480    let keyboardAvoidMode = windowStage.getMainWindowSync().getUIContext().getKeyboardAvoidMode();
481  windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET_WITH_CARET);
482    if (err.code) {
483      hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
484      return;
485    }
486    hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
487  });
488}
489```
490
491```ts
492// xxx.ets
493@Entry
494@Component
495struct Index {
496  @State caretPosition: number = 600;
497  areaController: TextAreaController = new TextAreaController();
498  text = "Most of us compare ourselves with anyone we think is happier — a relative, someone we know a lot, or someone we hardly know. As a result, what we do remember is anything that makes others happy, anything that makes ourselves unhappy, totally forgetting that there is something happy in our own life.\
499  So the best way to destroy happiness is to look at something and focus on even the smallest flaw. It is the smallest flaw that would make us complain. And it is the complaint that leads to us becoming unhappy.\
500  If one chooses to be happy, he will be blessed; if he chooses to be unhappy, he will be cursed. Happiness is just what you think will make you happy.Most of us compare ourselves with anyone we think is happier — a relative, someone we know a lot, or someone we hardly know. As a result, what we do remember is anything that makes others happy, anything that makes ourselves unhappy, totally forgetting that there is something happy in our own life.\
501  ";
502
503  build() {
504    Scroll() {
505      Column() {
506        Row() {
507          Button('CaretPosition++: ' + this.caretPosition).onClick(() => {
508            this.caretPosition += 1;
509          }).fontSize(10)
510          Button('CaretPosition--: ' + this.caretPosition).onClick(() => {
511            this.caretPosition -= 1;
512          }).fontSize(10)
513          Button('SetCaretPosition: ').onClick(() => {
514            this.areaController.caretPosition(this.caretPosition);
515          }).fontSize(10)
516        }
517
518        TextArea({ text: this.text, controller: this.areaController })
519          .width('100%')
520          .fontSize('20fp')
521      }
522    }.width('100%').height('100%')
523  }
524}
525```
526
527![textinputkeyboardavoid](figures/caretavoid.gif)
528
529## 相关实例
530
531针对文本输入开发,有以下相关实例可供参考:
532
533- [聊天实例应用(ArkTS)](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/Solutions/IM/Chat#%E8%81%8A%E5%A4%A9%E5%AE%9E%E4%BE%8B%E5%BA%94%E7%94%A8)