一、背景
在开发鸿蒙 APP 登录页时,会遇到这样的体验问题,当用户点击输入框弹出软键盘时,整个页面会被默认的上推模式带起,导致顶部的标题栏被推出可视区域,严重影响用户体验。
备注:以下解决方法为(API 11+),低版本不适配哦!
二、具体问题
页面分为三个部分,顶部固定标题,中间是logo图标,底部是输入框。用户点击底部输入框时,页面弹出软键盘,顶部固定标题没有固定住,整体往上移动。
问题效果预览:图1是没弹出软键盘的场景,图2是弹出软键盘的场景。


问题代码示例如下:
TypeScript
@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({ top: 200, left: 32, right: 32 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Start)
}
}
.width('100%')
.height('100%')
}
}
三、问题定位
3.1、确定问题
标题栏无固定布局,依赖页面整体排版,键盘弹起时随页面上移丢失
首先默认场景下UI是没有啥问题的,主要是在键盘弹起后UI整体上移了,那问题就出现键盘弹起的过程上,是没有正确配置键盘避让模式
3.2、键盘背景知识:
KeyboardAvoidMode配置键盘避让页面的避让模式,其中KeyboardAvoidMode.RESIZE表示压缩模式

四、解决问题
核心方案:配置setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE)(API 11+)
解决软键盘弹出后顶部控件无法固定的问题,可以通过setKeyboardAvoidMode来配置虚拟键盘弹出时,页面的避让模式为压缩模式。
在aboutToAppear生命周期里面配置键盘避让模式为压缩模式👇
