鸿蒙中 ​​Keyboard软键盘的弹出与隐藏

本文同步发表于微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、软键盘

   软键盘是用户交互的重要途径,提供文本输入功能。HarmonyOS支持在使用输入框组件(如TextInput、TextArea、Search、RichEditor)时,控制软键盘的弹出和收起行为。

二、弹出软键盘的方式

1. 自动弹出

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

2. 焦点转移方式

(1)人机交互获得焦点
  • 用户通过点击、双击、长按输入框等方式获取焦点。

(2)通过代码设置焦点
  • 使用 requestFocus() 或 defaultFocus() 方法将焦点转移到输入框。

代码:通过按钮点击请求焦点

@Entry
@Component
struct demo {
  controller: TextInputController = new TextInputController();
  @State inputValue: string = "";
  
  build() {
    Column({ space: 20 }) {
      Button('输入框请求焦点').onClick(() => {
        this.getUIContext().getFocusController().requestFocus("textInput123")
      })
      
      TextInput({ controller: this.controller, text: this.inputValue })
        .id("textInput123")
    }
    .height('100%')
    .width('80%')
    .margin('10%')
    .justifyContent(FlexAlign.Center)
  }
}
3)使用外接键盘按键走焦
  • 外接物理键盘时,按Tab、Shift+Tab、方向键可转移焦点。

3. 软键盘类型与属性控制

  • 系统软键盘:受 enableKeyboardOnFocus 属性影响

  • 自定义键盘:不受 enableKeyboardOnFocus 影响

三、收起软键盘的方式

1. 常见收起场景

(1)用户主动点击软键盘的关闭按钮
(2)拖拽文本
(3)页面切换
(4)通过输入框的controller退出编辑态

代码:

@Entry
@Component
struct demo {
  controller: TextInputController = new TextInputController();
  @State inputValue: string = "";
  
  build() {
    Column({ space: 30 }) {
      Button('关闭键盘').onClick(() => {
        this.controller.stopEditing()
      })
      TextInput({ controller: this.controller, text: this.inputValue })
    }
    .width('80%')
    .height('100%')
    .margin('10%')
    .justifyContent(FlexAlign.Center)
  }
}
(5)焦点转移到不需要软键盘的组件

代码1:焦点转移到按钮

@Entry
@Component
struct TextInputExample {
  controller: TextInputController = new TextInputController();
  @State inputValue: string = "";
  
  build() {
    Column({ space: 20 }) {
      Button('change 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%')
  }
}

代码2:List滚动时收起键盘

@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(() => {
        this.getUIContext().getFocusController().clearFocus()
      })
      .width('80%')
      .height('80%')
      .margin('10%')
    }
    .justifyContent(FlexAlign.Center)
  }
}

四、常见问题

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

代码:设置空自定义键盘

@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%')
  }
}

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

代码:使用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) => {
          event.keepEditableState();
        })
    }
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('80%')
    .margin('10%')
  }
}

五、相关API与属性

焦点控制:

  • requestFocus() / defaultFocus() - 请求焦点

  • clearFocus() - 清除焦点

  • focusable() - 设置组件可获焦

输入框控制:

  • TextInputController.stopEditing() - 退出编辑态

  • enableKeyboardOnFocus - 控制焦点转移时是否弹出系统键盘

  • customKeyboard() - 设置自定义键盘

  • enterKeyType - 设置回车键类型

  • onSubmit - 回车键提交事件

  • keepEditableState() - 保持编辑态

<think> 根据引用内容,用户的问题是关于在ArkUI半模态页面中,输入框软键盘弹起后页面内容高度被顶起,但软键盘退下后页面内容高度没有恢复的问题。这类似于微信小程序或uniapp中遇到的键盘弹起导致页面上移的问题。 分析引用中的解决方案: 1. 引用[1][2]:在微信小程序中,通过动态计算键盘高度,调整输入框容器的`bottom`值,使得输入框跟随键盘上移,同时固定顶部区域。在键盘收起时将`bottom`重置为0。 2. 引用[3]:同样在微信小程序中,通过监听输入框的聚焦(focus)和失焦(blur)事件,在聚焦时设置输入框容器的`bottom`值为键盘高度,失焦时重置为0。 3. 引用[4]:在uniapp中,通过在页面配置中设置`softinputMode`为`adjustResize`,让页面自动调整大小以适应软键盘。 现在问题出现在ArkUI的半模态页面(可能是自定义弹窗或底部弹出的半屏页面)中,当软键盘弹起时,页面内容高度被顶起(高挡位),但软键盘退下后,页面内容高度没有恢复(仍处于高挡位,即低挡位状态?这里描述有些歧义,用户说“退下后页面内容高度仍为低挡位状态”,但根据上下文,应该是键盘弹起后页面被顶起(高挡位),键盘收起后页面没有恢复(即仍然处于被顶起的高挡位,而不是原来的低挡位)。所以我们需要的是键盘收起后页面恢复原来的位置(即低挡位)。 在ArkUI中,我们可以考虑以下方案: 1. 使用`flex`布局,将页面分为两部分:顶部固定内容(不变)和底部输入区域(跟随键盘移动)。 2. 监听软键盘事件,动态调整底部输入区域的位置(类似于微信小程序的做法)。 3. 使用`position: fixed`来固定底部输入框,当键盘弹起时,通过计算键盘高度来调整输入框的底部距离;键盘收起时,恢复到底部。 但是,ArkUI(HarmonyOS)目前对软键盘事件的监听支持有限,我们可以通过以下步骤实现: - 在页面的`onPageShow`生命周期中,监听键盘高度变化(使用`@ohos.keyboard`模块)。 - 在键盘高度变化时,动态设置底部输入框的`bottom`值。 - 注意:半模态页面通常是一个自定义弹窗,我们需要确保弹窗内的布局能够响应键盘高度的变化。 具体步骤: 1. 导入键盘模块:`import keyboard from '@ohos.keyboard'`。 2. 在页面中,定义一个状态变量`keyboardHeight`,用于存储当前键盘的高度(初始为0)。 3. 注册键盘高度变化事件:`keyboard.on('keyboardHeightChange', (height) => { ... })`。 4. 在事件回调中,将`keyboardHeight`设置为当前高度(键盘弹起时高度>0,收起时为0)。 5. 将输入框容器的底部样式设置为`keyboardHeight`(当键盘弹起时,输入框底部距离为键盘高度;键盘收起时,距离为0)。 示例代码(ArkUI的声明式UI范式): ```typescript // 引入keyboard模块 import keyboard from '@ohos.keyboard' @Entry @Component struct HalfModalPage { @State keyboardHeight: number = 0 onPageShow() { // 注册键盘高度变化事件 keyboard.on('keyboardHeightChange', (height: number) => { this.keyboardHeight = height }) } onPageHide() { // 取消注册 keyboard.off('keyboardHeightChange') } build() { Column() { // 页面主要内容区域 Scroll() { // ... 其他内容 } .flexGrow(1) // 底部输入框区域 Row() { TextInput({ placeholder: '请输入' }) .width('80%') Button('发送') .width('20%') } .width('100%') .padding(10) .backgroundColor(Color.White) .position({ bottom: this.keyboardHeight }) // 动态调整底部距离 } .width('100%') .height('100%') } } ``` 注意:上述代码中,底部输入框区域使用绝对定位(通过`position`设置),当键盘弹起时,键盘高度会作为`bottom`值,这样输入框就会上移到键盘上方。键盘收起时,`keyboardHeight`变为0,输入框恢复到底部。 但是,半模态页面通常是一个自定义弹窗,可能会覆盖在页面上。因此,我们需要确保半模态页面的高度和定位方式能够适应键盘的变化。 另外,如果半模态页面使用自定义弹窗(CustomDialog),那么我们需要在弹窗内部实现上述逻辑。同时,由于弹窗本身可能已经使用了绝对定位或固定定位,我们可以直接调整弹窗内部输入框的位置。 如果上述方法无法解决,可以尝试在弹窗的根节点使用`flex`布局,并设置`flex-direction: column`,将输入框区域放在底部,并设置`marginBottom`为键盘高度(但这样可能会压缩内容区域)。或者,我们也可以将弹窗的高度设置为减去键盘高度后的值。 总结:核心思路是监听键盘高度变化,并动态调整输入框的底部距离(或整个弹窗的高度),以确保键盘弹起时输入框上移,键盘收起时恢复原位置。 相关问题: 1. 如何在ArkUI中监听软键盘高度变化? 2. 半模态页面的布局方式有哪些? 3. 如何防止软键盘遮挡输入框? 4. 在HarmonyOS中,如何实现输入框始终在软键盘上方? </think> ### 解决 ArkUI 半模态页面软键盘高度残留问题 在 ArkUI 半模态页面中,软键盘弹起后页面高度被顶起(高挡位),但键盘收起后高度未恢复(低挡位)的问题,可通过以下方案解决: #### 核心解决方案 ```typescript // 1. 监听键盘高度变化 import keyboard from '@ohos.keyboard'; @State keyboardHeight: number = 0; private keyboardHeightListener = keyboard.on('keyboardHeightChange', (height) => { this.keyboardHeight = height; // 键盘高度变化时更新状态 }); // 2. 动态控制页面高度 build() { Column() { // 页面主要内容 (高度自适应) Scroll() { ... } .flexGrow(1) // 关键:内容区域自动填充剩余空间 // 底部输入框区域 Row() { TextInput() .onFocus(() => this.keyboardStatus = 'open') .onBlur(() => this.keyboardStatus = 'close') Button('发送') } .position({ bottom: this.keyboardHeight }) // 动态底部距离 .backgroundColor(Color.White) } .height('100%') // 关键:容器高度始终占满父组件 .onDisappear(() => { this.keyboardHeightListener.off(); // 销毁监听器 }) } ``` #### 关键技术点 1. **键盘高度监听**: - 使用 `@ohos.keyboard` 模块监听 `keyboardHeightChange` 事件 - 实时更新 `keyboardHeight` 状态变量记录当前键盘高度 2. **动态布局控制**: - 主容器设置 `height('100%')` 保持全屏高度 - 内容区域使用 `flexGrow(1)` 自动伸缩填充空间 - 输入框容器通过 `position({ bottom: keyboardHeight })` 动态调整位置 3. **恢复机制**: - 键盘收起时 `keyboardHeight` 自动归零 - 页面布局自动回弹到原始位置 - 使用 `onBlur` 事件作为键盘收起的补充检测 4. **半模态页面特殊处理**: ```typescript // 半模态弹窗需显式设置高度 CustomDialog(this, { height: '60%', // 固定高度百分比 builder: () => { Column() { ... }.height('100%') // 内部容器占满弹窗高度 } }) ``` #### 备选方案 (API兼容) ```typescript // 适用于旧版本API import window from '@ohos.window'; window.getTopWindow().then(win => { win.on('keyboardHeightChange', (height) => { this.keyboardHeight = height; }); }); ``` #### 注意事项 1. **布局层级**: - 避免在滚动容器内嵌套输入框 - 输入框应直接放在页面级容器中 2. **系统差异**: ```typescript // Android/iOS兼容处理 .position({ bottom: platform.OS === 'ios' ? this.keyboardHeight : Math.max(0, this.keyboardHeight - 48) }) ``` 3. **内存管理**: - 页面销毁时调用 `listener.off()` 解除监听 - 使用 `onPageHide`/`onDisappear` 生命周期释放资源 > 通过动态绑定 `keyboardHeight` 到布局的 `bottom` 属性,实现键盘弹起时输入框上移,键盘收起时自动恢复原始位置。核心在于保持页面容器高度恒定,由 Flex 布局自动处理内容区域的空间分配[^1][^2][^3]。 --- ### 相关问题 1. 如何检测 ArkUI 中软键盘弹出和收起状态? 2. HarmonyOS 中不同页面模式(全屏/半模态)如何处理键盘事件差异? 3. 当输入框被自定义键盘遮挡时,如何动态滚动页面到可见区域? 4. 在 ArkUI 的 List 组件中,如何实现输入框随键盘弹出自动定位到屏幕中部? 5. 如何处理软键盘弹出时页面背景内容被压缩变形的问题?[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值