跳到主要内容

管理软键盘

软键盘是用户交互的重要途径,提供文本输入功能。本文介绍在使用系统输入框组件(TextInputTextAreaSearchRichEditor)时,如何控制软键盘的弹出和收起。

弹出软键盘

默认情况下,当焦点转移到输入框时,软键盘将自动弹出。

焦点转移到输入框的方法主要有:

  1. 人机交互获得焦点,例如:单击、双击、长按输入框。
  2. 通过代码设置焦点,例如:使用requestFocusdefaultFocus方法,将焦点转移到输入框。
  3. 使用外接键盘的按键走焦,例如:Tab键、Shift+Tab键、方向键,按下后可以转移焦点。外接键盘时输入框获焦,不会弹出系统软键盘,会显示物理键盘悬浮栏。

软键盘分为系统软键盘和自定义键盘。输入框的enableKeyboardOnFocus属性会影响系统软键盘弹出。当enableKeyboardOnFocus属性设置为false时,只有通过点击、按键走焦才能弹出系统软键盘。enableKeyboardOnFocus属性对自定义键盘的弹出无影响。外接物理键盘会阻止弹出系统软键盘,对自定义键盘无影响。

人机交互获得焦点

以下示例展示了单击、双击和长按输入框时,软键盘弹出效果。

通过代码请求焦点

可以通过代码控制将焦点转移到输入框,包括使用defaultFocusrequestFocus方法。更多细节请参见支持焦点处理

以下示例展示了点击按钮时,焦点转移到输入框并弹出软键盘的方法。

@Entry
@Component
struct demo {
controller: TextInputController = new TextInputController();
@State inputValue: string = "";

build() {
Column({ space: 20 }) {
Button('输入框请求焦点').onClick(() => {
this.getUIContext().getFocusController().requestFocus("textInput1")
})
TextInput({ controller: this.controller, text: this.inputValue })
.id("textInput1")
}
.height('100%')
.width('80%')
.margin('10%')
.justifyContent(FlexAlign.Center)
}
}

使用外接键盘的按键走焦

外接物理键盘时,按下物理键盘的Tab键、Shift+Tab键、方向键可以转移焦点。按键走焦到输入框时,显示物理键盘悬浮栏。更多细节请参见支持焦点处理

以下示例展示了外接键盘时,多次按下Tab键,焦点转移到TextInput并弹出软键盘的场景。当按下Tab键时,焦点在页面中的三个组件之间转移,可以从Text的蓝色边框或者TextInput中闪烁的光标观察到焦点转移。当TextInput获焦时,显示光标,同时显示物理键盘悬浮栏。

@Entry
@Component
struct Index {
build() {
Column({ space: 20 }) {
Text('Text.focusable(true)')
.focusable(true)

TextInput({ placeholder: "TextInput" })

TextInput({ placeholder: "TextInput" })
}
.height('100%')
.width('80%')
.margin('10%')
.justifyContent(FlexAlign.Center)
}
}

收起软键盘

当输入框获得焦点时,软键盘会弹出;然而,当输入框失焦时,软键盘不会自动收起,而是由下一个获得焦点的组件决定是否收起软键盘。如果该组件需要使用软键盘,软键盘将继续显示;如果该组件不需要软键盘,则软键盘将被收起。通常情况下,除输入框外的其他组件不需要软键盘。

收起软键盘的常见场景如下所示,下列场景都会将焦点转移到不需要软键盘的组件上并收起软键盘。

  1. 用户主动点击软键盘的关闭按钮。
  2. 用户正在拖拽文本。
  3. 输入框接收到了侧滑手势。
  4. 页面发生切换。
  5. 通过输入框的TextInputController退出编辑态。
  6. 焦点从输入框转移到另一个不需要软键盘的组件。

点击软键盘的关闭按钮

软键盘自带关闭按钮,用户点击该按钮时,软键盘将被收起。

以下示例展示了用户主动点击软键盘关闭按钮的场景。

@Entry
@Component
struct Index {
build() {
Column({ space: 20 }) {
Blank()
.height(350)
Flex({ direction: FlexDirection.Row }) {
TextInput({ placeholder: 'TextInput' })
}
.width(250)
}
.height('100%')
.width('90%')
.padding('5%')
}
}

拖拽文本

用户主动拖拽输入框的文本,开始拖拽时,软键盘将收起。更多细节请参见支持统一拖拽

以下示例展示了用户主动拖拽文本时,软键盘被收起的场景。

@Entry
@Component
struct Index {
build() {
Column({ space: 20 }) {
Blank()
.height(350)
Flex({ direction: FlexDirection.Row }) {
TextInput({ text: '用户主动拖拽文本' })
.selectAll(true)
.defaultFocus(true)
}
.width(250)
}
.height('100%')
.width('90%')
.padding('5%')
}
}

接收侧滑手势

下面的动图展示了“用户侧滑时软键盘收起”的场景。

页面发生切换

以下示例展示了页面切换过程中,软键盘收起的场景。

页面跳转写法请参考Navigation页面路由

跳转前的页面

// Index.ets
@Entry
@Component
struct Index {
// 创建一个导航控制器对象并传入Navigation
pathStack: NavPathStack = new NavPathStack()

build() {
Navigation(this.pathStack) {
Column({ space: 30 }) {
Blank().height(150)
TextInput({ placeholder: 'TextInput' })
Button('跳转到下一个页面')
.onClick(() => {
this.pathStack.pushPath({ name: 'demo_text_1' })
})
}
.height('100%')
.width('80%')
.margin('10%')
}
.title('用Navigation实现页面跳转')
}
}

跳转后的页面

// demo_text_1.ets
@Builder
export function demo_text_1_Builder() {
demo_text_1()
}

@Component
struct demo_text_1 {
pathStack: NavPathStack = new NavPathStack()
// 跳转后的页面
build() {
NavDestination() {
Column({ space: 20 }) {
Text('跳转后的页面没有需要键盘的组件')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
.onReady((context: NavDestinationContext) => {
this.pathStack = context.pathStack
})
}
}

系统路由表配置

在跳转目标模块的配置文件module.json5添加路由表配置

{
"module": {
// ...
"routerMap": "$profile:route_map",
// ...
}
}

在工程resources/base/profile中创建route_map.json文件。添加如下配置信息。

// route_map.json
{
"routerMap": [
{
"name": "demo_text_1",
"pageSourceFile": "src/main/ets/pages/demo_text_1.ets",
"buildFunction": "demo_text_1_Builder"
}
]
}

通过输入框的controller退出编辑态

通过输入框的TextInputController调用stopEditing方法后,软键盘会自动收起。

以下示例展示了如何通过TextInputController收起软键盘。

struct textInputControllerCloseKeyboard {
controller: TextInputController = new TextInputController();
@State inputValue: string = '';

build() {
NavDestination() {
Column({ space: 30 }) {
// 请将$r('app.string.close_keyboard')替换为实际资源文件,在本示例中该资源文件的value值为"close keyboard"
Button($r('app.string.close_keyboard')).onClick(() => {
this.controller.stopEditing()
})
TextInput({ controller: this.controller, text: this.inputValue })
}
.width('80%')
.height('100%')
.margin('10%')
.justifyContent(FlexAlign.Center)
}
}
}

焦点转移到不需要软键盘的组件

焦点转移到不需要软键盘的组件时,软键盘会自动收起。

代码控制焦点转移的方法,包括requestFocusclearFocus。更多细节请参见支持焦点处理

与通过输入框的controller退出编辑态方法相比,焦点转移到不需要软键盘的组件方法的优势在于,页面包含多个输入框时,开发者无需为每个输入框设置controller、再通过controller收起软键盘。

以下示例展示了点击按钮时,调用requestFocus方法,焦点从输入框转移到按钮上,软键盘收起的场景。

struct requestFocusCloseKeyBoard {
controller: TextInputController = new TextInputController();
@State inputValue: string = '';

build() {
NavDestination() {
Column({ space: 20 }) {
// 请将$r('app.string.button_get_focus')替换为实际资源文件,在本示例中该资源文件的value值为"按钮获得焦点"
Button($r('app.string.button_get_focus')).onClick(() => {
this.getUIContext().getFocusController().requestFocus('button')
}).id('button')
TextInput({ controller: this.controller, text: this.inputValue })
}
.justifyContent(FlexAlign.Center)
.height('100%')
.width('80%')
.margin('10%')
}
}
}

以下示例展示了滚动容器在开始滚动时收起键盘的场景。List开始滚动时,调用clearFocus方法清理焦点,焦点转移到页面根容器节点,页面根容器节点不需要软键盘,从而收起软键盘。

@Entry
@Component
struct Index {
private arr: number[] = Array.from<number, number>(
{ length: 100 } as ArrayLike<number>,
(_, i: number) => i + 1
);

build() {
Column() {
List({ space: 20, initialIndex: 0 }) {
ForEach(this.arr, (item: number, index?: number) => {
ListItem() {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
TextInput({ placeholder: 'TextInput ' + item })
}
}
}, (item: string) => item)
}
.onScrollStart(() => {
// List开始滚动时清理焦点,达成收起键盘的目的
this.getUIContext().getFocusController().clearFocus()
})
.width('80%')
.height('80%')
.margin('10%')
}
.justifyContent(FlexAlign.Center)
}
}

常见问题

在软键盘的实际应用中,开发者可能会遇到一些特殊的使用场景或个性化需求。本节将针对这些常见问题提供相应的解决方案,帮助开发者更好地控制软键盘的行为。

获得焦点时阻止弹出软键盘

问题现象

如何实现点击输入框时,不弹出软键盘?

原因分析

默认情况下,点击输入框后,输入框获得焦点,会自动弹出系统软键盘。通过customKeyboard设置自定义键盘之后,输入框获焦时不会弹出系统软键盘,改为弹出自定义键盘。

解决措施

设置自定义键盘后,系统键盘不会弹出。利用此特性,设置一个空的自定义键盘,实现“点击输入框时不显示软键盘”的效果。

示例如下,单击输入框,拉起空的自定义键盘。

@Entry
@Component
struct demo {
controller: TextInputController = new TextInputController();
@State inputValue: string = "";

// 自定义键盘组件
@Builder
CustomKeyboardBuilder() {
Column() {
}
}

build() {
Column() {
TextInput({ placeholder: 'TextInput', controller: this.controller, text: this.inputValue })// 绑定自定义键盘
.customKeyboard(this.CustomKeyboardBuilder())
}
.justifyContent(FlexAlign.Center)
.width('80%')
.margin('10%')
.height('100%')
}
}

点击发送按钮后不收起键盘

问题现象

如何实现点击软键盘发送按钮之后,软键盘不收起?

原因分析

软键盘的enterKeyType可以设置输入法回车键类型,包括发送样式。按下发送按钮实际上是按下回车键,非TV设备按下回车键时,输入框默认会失焦并且收起键盘。

解决措施

软键盘的enterKeyType可以设置输入法回车键类型。除EnterKeyType.NEW_LINE外,enterKeyType设置其他的枚举值时,按下软键盘输入法回车键都会触发onSubmit事件。可以在TextArea的onSubmit回调中,通过调用keepEditableState接口保持输入框编辑态,使得点击回车键后不收起键盘。

示例如下,软键盘的回车键显示为发送样式。按下发送之后,键盘不会收起。

@Entry
@Component
struct demo {
build() {
Column({ space: 20 }) {
TextArea({ placeholder: '点击发送收起键盘' })
.enterKeyType(EnterKeyType.Send)

TextArea({ placeholder: 'onSubmit中设置keepEditableState,点击发送不收起键盘' })
.enterKeyType(EnterKeyType.Send)
.onSubmit((enterKey: EnterKeyType, event: SubmitEvent) => {
// 调用keepEditableState方法,输入框保持编辑态
event.keepEditableState();
})
}
.justifyContent(FlexAlign.Center)
.height('100%')
.width('80%')
.margin('10%')
}
}