在 HarmonyOS 中,控制输入框的焦点与键盘显隐,核心思路是通过 defaultFocus 实现页面进入自动获焦,通过 focusControl.requestFocus 实现动态切换,并通过 onFocus / onBlur 监听状态变化。以下是具体实现方案。


一、核心原理

输入框(TextInput)与键盘的联动遵循一个基本规则:键盘的显隐与输入框的焦点状态绑定。 当一个输入框获得焦点时,系统软键盘会自动弹出;当它失去焦点时,键盘会收起 。

二、进入页面默认弹出键盘

在页面加载后,希望输入框自动获得焦点并弹出键盘,最直接的方式是使用 defaultFocus 属性。

typescript

TextInput()
  .id('myInput')
  .defaultFocus(true) // 页面首次进入时,该组件自动获焦,弹出键盘
  .onFocus(() => {
    console.log('输入框已获焦,键盘弹出');
  })

注意事项

  • defaultFocus 仅在页面初次创建并第一次进入时生效。对于被 if 条件控制显隐的自定义组件,或二次进入页面时,它不会生效 。

  • 若页面内多个组件设置了 defaultFocus(true),系统会以组件树深度遍历找到的第一个为准 。

API 11 行为变更:在 API 11 及之后版本,如果没有任何组件设置 defaultFocus(true),页面首次打开时默认焦点将落在根容器上,而不会自动聚焦到第一个可获焦的非容器组件 。

三、主动控制焦点与键盘显隐

当你需要动态控制键盘弹出或收起(如点击按钮让某个输入框获焦,或点击空白区域收起键盘)时,可以使用 focusControl

1. 主动获取焦点(弹出键盘)

调用 requestFocus 方法,让焦点转移到指定的输入框上,从而拉起键盘。

typescript

// 推荐写法(API 12 及以上,可捕获错误码)
this.getUIContext().getFocusController().requestFocus('myInput');

// 或传统写法
focusControl.requestFocus('myInput');

应用场景:当某个输入框因被 if 隐藏后重新显示,需要自动获焦时,可在显示逻辑后调用此方法 。

2. 主动清除焦点(收起键盘)

调用 clearFocus 方法,将焦点强制转移到页面的根容器上,此时所有输入框失去焦点,键盘收起。

typescript

this.getUIContext().getFocusController().clearFocus();

另一种技巧:通过动态修改 focusable 属性为 false,也可以强制当前输入框失去焦点,焦点会转移到下一个可获焦的组件 。

四、监听焦点状态与键盘显隐

1. 监听焦点变化

通过 onFocus 和 onBlur 回调,可以精确感知输入框的获焦和失焦瞬间。

typescript

TextInput()
  .onFocus(() => {
    // 获焦逻辑:例如修改UI样式,记录埋点
  })
  .onBlur(() => {
    // 失焦逻辑:例如校验输入内容
  })
2. 监听键盘高度变化(判断键盘显隐)

除了焦点监听,有时业务需要监听键盘的弹出与收起(例如调整页面布局)。可以通过窗口模块监听键盘高度变化 。

typescript

import { window } from '@kit.ArkUI';

let windowClass: window.Window | undefined = undefined;
window.getLastWindow(this.context, (err, data) => {
  windowClass = data;
  // 监听键盘高度变化
  windowClass.on('keyboardHeightChange', (height: number) => {
    if (height > 0) {
      console.log('键盘已弹出,高度为:' + height);
      // 执行键盘弹出时的UI适配逻辑
    } else {
      console.log('键盘已收起');
      // 执行键盘收起时的UI适配逻辑
    }
  });
});

五、进阶控制与特性

1. enableKeyboardOnFocus:获焦不弹键盘

默认情况下,输入框获焦就会弹键盘。若你希望输入框获得焦点(例如用于粘贴操作)但暂时不弹出键盘,可以将此属性设为 false 。

typescript

TextInput()
  .defaultFocus(true)
  .enableKeyboardOnFocus(false) // 获焦了,但不弹键盘
2. 自定义键盘:完全接管键盘逻辑

如果需要使用自定义组件替代系统键盘,可以利用 customKeyboard 属性。此时输入框获焦后,不会弹出系统键盘,而是显示你定义的自定义组件 。

typescript

@Builder
function MyCustomKeyboard() {
  Column() {
    Button('自定义按键1')
    Button('自定义按键2')
  }
  .width('100%')
  .backgroundColor(Color.Gray)
}

TextInput()
  .customKeyboard(MyCustomKeyboard()) // 获焦后显示自定义键盘

六、常见问题 FAQ

1. 为什么 defaultFocus(true) 在自定义组件中不生效?
defaultFocus 仅在页面(Page)首次创建时生效。如果自定义组件是在页面加载后动态渲染(如被 if 控制),需要使用 requestFocus 主动请求焦点 。

2. 如何调试复杂的焦点问题?

  • 查看焦点树:通过 hdc shell "hidumper -s WindowManagerService -a '-w [winId] -focus'" 可以输出当前界面的焦点树,* 标记的节点即为当前获焦节点 。

  • 过滤焦点日志:在真机上根据关键词 AceFocus|AceKeyboard 过滤日志,有助于排查焦点与键盘的联动问题 。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐