当前位置: 首页 > news >正文

【HarmonyOS NEXT】如何监听软键盘的弹出和收起事件

一、背景

在开发鸿蒙 APP 登录页时,当输入框键盘弹起,需要改变logo图标与输入框的间距,让整个页面完全展示,提升用户体验

二、具体问题

默认情况下,logo图标与标题栏和输入框给的固定间距,页面能够完全展示,但当键盘弹起时,输入框被遮挡,用户输入了手机号或验证码,但完全看不到自己输入的内容,很影响用户体验

问题效果预览:

问题代码示例如下:

@Extend(TextInput) function commonInputStyle(maxLength: number) { .placeholderColor('#999999') .borderRadius(8) .contentType(ContentType.PHONE_NUMBER) .caretStyle({ color: '#b35336', width: 2 }) .height(48) .maxLength(maxLength) .maxLines(1) .type(InputType.Number) .fontColor('#333333') .width("100%") .backgroundColor(Color.White) .padding({ left: 16, right: 16 }) .shadow({ radius: 4, color: '#00000008', offsetY: 2 }) } @Entry @Component export struct Index { @State phoneNumber: string = "" @State codeNumber: string = "" build() { Column() { Stack({ alignContent: Alignment.Top }) { Column() .width('100%') .height('100%') .backgroundColor('#F8F9FA') // 标题栏 Column() { Text('密码登录') .fontColor('#333333') .fontSize(20) .fontWeight(500) .margin({ top: 10 }) // logo模块 Image($r("app.media.startIcon")) .width(120) .objectFit(ImageFit.Contain) .margin({ top: 110, bottom: 60 }) .borderRadius(16) .shadow({ radius: 8, color: '#00000010', offsetY: 4 }) // 输入模块 Column() { TextInput({ text: this.phoneNumber, placeholder: "请输入手机号" }) .commonInputStyle(11) .onChange((value: string) => { this.phoneNumber = value }) TextInput({ text: this.codeNumber, placeholder: "请输入短信验证码" }) .commonInputStyle(6) .margin({ top: 20 }) .onChange((value: string) => { this.codeNumber = value }) } .width('100%') .padding({ left: 32, right: 32 }) .margin({ top: 200 }) } .width('100%') .height('100%') .justifyContent(FlexAlign.Start) } } .width('100%') .height('100%') } }

三、期望效果

当点击输入框键盘弹起时,改变logo图标与标题栏和输入框的间距,让内容能够完全展现

四、解决方案

4.1、方案1:使用输入框的焦点事件

使用输入框的焦点事件:通过TextInput组件的onFocus和onBlur事件可以间接判断键盘的弹出和收起。当输入框获得焦点时,通常会触发键盘弹出;当输入框失去焦点时,键盘会收起。

@State inputMarginTop: number = 200; // 初始值:无键盘时输入框与logo的间距 @State logoMarginTop: number = 110; //初始值:无键盘时logo与标题的间距 TextInput({ text: this.phoneNumber, placeholder: "请输入手机号" }) .commonInputStyle(11) .onChange((value: string) => { this.phoneNumber = value }) .onFocus(() => { console.log('lucy== 手机号---输入框获焦,键盘已弹出'); this.inputMarginTop = 100 this.logoMarginTop = 50 }) .onBlur(() => { console.log('lucy== 手机号---输入框失焦,键盘已收起'); this.inputMarginTop = 200 this.logoMarginTop = 110 })

备注:此种场景会有个问题,假如有多个输入框,需要给每个输入框都设置焦点事件

4.2、方案2:开启固定态软键盘高度变化的监听

监听键盘高度变化:通过window.on('keyboardHeightChange')事件可以监听键盘的高度变化。当键盘弹出时,返回的高度值为非零值;当键盘收起时,返回的高度值为0。

currentWindow.on('keyboardHeightChange', (data) => { if (data > 0) { console.info('键盘高度大于0,键盘已弹出'); } else { console.info('键盘高度为0,键盘已收起'); } });

完整示例参考如下:

import { KeyboardAvoidMode, window } from '@kit.ArkUI'; @Extend(TextInput) function commonInputStyle(maxLength: number) { .placeholderColor('#999999') .borderRadius(8) .contentType(ContentType.PHONE_NUMBER) .caretStyle({ color: '#b35336', width: 2 }) .height(48) .maxLength(maxLength) .maxLines(1) .type(InputType.Number) .fontColor('#333333') .width("100%") .backgroundColor(Color.White) .padding({ left: 16, right: 16 }) .shadow({ radius: 4, color: '#00000008', offsetY: 2 }) } @Entry @Component export struct Index { @State phoneNumber: string = "" @State codeNumber: string = "" @State inputMarginTop: number = 200; // 初始值:无键盘时输入框与logo的间距 @State logoMarginTop: number = 110; //初始值:无键盘时logo与标题的间距 aboutToAppear(): void { this.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE); // 设置键盘避让模式 window.getLastWindow(this.getUIContext().getHostContext()).then(currentWindow => { currentWindow.on('keyboardHeightChange', (data) => { if (data > 0) { console.log('lucy== 键盘高度大于0,键盘已弹出'); this.inputMarginTop = 100 this.logoMarginTop = 50 } else { console.log('lucy== 键盘高度为0,键盘已收起'); this.inputMarginTop = 200 this.logoMarginTop = 110 } }); }); } build() { Column() { Stack({ alignContent: Alignment.Top }) { Column() .width('100%') .height('100%') .backgroundColor('#F8F9FA') // 标题栏 Column() { Text('密码登录') .fontColor('#333333') .fontSize(20) .fontWeight(500) .margin({ top: 10 }) // logo模块 Image($r("app.media.startIcon")) .width(120) .objectFit(ImageFit.Contain) .margin({ top: this.logoMarginTop, bottom: 60 }) .borderRadius(16) .shadow({ radius: 8, color: '#00000010', offsetY: 4 }) // 输入模块 Column() { TextInput({ text: this.phoneNumber, placeholder: "请输入手机号" }) .commonInputStyle(11) .onChange((value: string) => { this.phoneNumber = value }) TextInput({ text: this.codeNumber, placeholder: "请输入短信验证码" }) .commonInputStyle(6) .margin({ top: 20 }) .onChange((value: string) => { this.codeNumber = value }) } .width('100%') .padding({ left: 32, right: 32 }) .margin({ top: this.inputMarginTop }) } .width('100%') .height('100%') .justifyContent(FlexAlign.Start) } } .width('100%') .height('100%') } }

4.3、实现效果

实现效果:键盘弹起时输入框不会被遮挡

结论:我选择的是方案二,因为当输入框多的情况下,需要给每个输入框添加焦点事件,而方案二只用监听键盘的高度变化来适配间距,更适合我当下的场景

http://www.cnnetsun.cn/news/669366.html

相关文章:

  • 固定翼无人机俯仰姿态模糊PID控制(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码
  • ‌AI驱动的测试环境配置检查清单:全面指南
  • 领导说你潜力大,却不肯提拔你,只说明一件事
  • 2026 年前端必会的 10 个现代 CSS 布局技巧
  • 泊车十年演进
  • AI之LangChain:LangChain框架解读之工具调用和Agent逻辑实现细节梳理(并探讨与MCP和A2A关系)
  • 价值链视角下的YW公司成本控制研究
  • 互联网大厂Java小白求职面试:从缓存技术到微服务框架的循序渐进提问
  • 警惕新型网络攻击:MacStealer恶意软件借虚假ChatGPT指令传播
  • shell ${} 字符串替换和默认值设置教程
  • 宏桥收购鲁丰原因解读,产业链整合与战略分析
  • How to Queue Properly: Avoid Conflict and Wait Efficiently
  • 浏览器兼容问题全解析:前端必看实战解决方案
  • ‌异常流测试实战指南:网络中断、权限变更、存储满三大核心场景的深度设计与工程实践
  • 【Java毕设全套源码+文档】基于springboot村医疗管理系统的设计与实现(丰富项目+远程调试+讲解+定制)
  • 百度UEDITOR如何实现WORD公式粘贴后自动转存?
  • 藏在烟火里的经济密码:用博物经济学看懂日常
  • 学术探险家的秘密武器:书匠策AI如何重构本科论文写作地图
  • 导师推荐10个AI论文平台,自考学生轻松搞定毕业论文!
  • 智慧课堂教师行为检测数据集VOC+YOLO格式3898张6类别
  • shell参数空格处理技巧,带空格文件名传递方法
  • ssm609的班主任辅导员班级管理系统vue
  • paperxie 领衔:8 款 AI 毕业论文工具硬核横评,谁能帮你通关毕业季?
  • AI智能如何帮助我们寻找客户的新方法与实践探索
  • 专科生必备!10个高效降AI率工具推荐
  • 3.1 多模态AI革命:图像、文本、语音如何融合智能
  • 在 Ubuntu 上安装 noVNC
  • 1.2 深度学习核心概念一网打尽:神经网络、激活函数与损失函数详解
  • 2.1 Transformer解密:自注意力机制与位置编码全解析
  • 从部署到超越:YOLOv5s在RK3588上实现120FPS的完整优化路径与工程实践