欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > 鸿蒙开发:如何解决软键盘弹出后的间距

鸿蒙开发:如何解决软键盘弹出后的间距

2025/5/2 10:46:35 来源:https://blog.csdn.net/ming_147/article/details/147652631  浏览:    关键词:鸿蒙开发:如何解决软键盘弹出后的间距

前言

本文基于Api13

近日在查看github中的issue时,发现了一个问题,说的是当自定义弹窗中有TextInput组件时,触摸焦点弹起软键盘后,组件和软键盘之间有一个间距,看到问题后,“我就在想,自定义弹窗,所有的UI都是传入的,是不是在绘制的时候,这个间距是开发者加的呢?”,本着对问题负责的态度,于是就验证问题出现的原因,最后却发现这是鸿蒙系统的问题

为了验证问题,我传入的自定义UI,没有带有一丝间距,弹起后,发现了开发者所提的问题非虚,和软键盘之间,还真有一个小小的间距。

看着这个间距,发呆了3秒,彻底怀疑了人生,我明明没设置间距啊,但是这个间距从哪来的呢?是不是软键盘弹起后,本身就会有一个间距?

为了验证问题的真实性,我写了一个无比简单的代码,就一个Column组件包裹着一个TextInput组件,让TextInput组件在最底部,代码如下:

 Column() {TextInput()}.width("100%").height("100%").justifyContent(FlexAlign.End)}

运行,点击输入框:

运行之后,看着组件和软键盘之间的间距,陷入了沉思,“给我提问题那个朋友,这个问题,我不背锅”。

是不是TextInput组件有这个问题,换一个其他的输入组件就没这个问题了?于是,我又验证了TextArea,RichEditor,发现问题依然存在,显然和组件是没有关系,和软键盘有关系。
 

接着便查看了Dom结构,发现这是root根节点自带的一个间距。

打开Dom树结构,可以发现,父节点Column是没有间距的,但是距离软键盘那确实有一个间距。

点击root节点后,就会发现,这个间距是root所带的。

这就证明了一个问题,那就是,输入框和软键盘之间的间距是系统自带的,对比前后的高度,可以得出,这个间距是44px。

其实站在我的角度上去看,我觉得这个间距挺好,起码在UI视觉上看着美观。当然了不能我以为就以为,还是要考虑到实际的需求开发,毕竟有的场景下,就不需要间距。

有问题,就会有解决问题的办法,经过一系列的研究,其实解决起来也十分的简单,总结了有三种方式,大家可以选择适合的方式。

方式一:设置页面避让模式

当我们不设置虚拟键盘的避让模式时,默认是OFFSET模式,也就是上抬模式,就会出现间距的问题,我们可以改为压缩模式RESIZE。

 this.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE)

设置完避让模式后,我们再次运行看下,组件和软键盘之间的间距已经取消了。

 

方法二:设置沉浸式布局

设置沉浸式布局时,布局不会避让状态栏与导航栏,组件可能产生与其重叠的情况,这种情况下需要自己设置距离顶部和底部的距离。


 window.getLastWindow(getContext(), (_, win) => {win.setWindowLayoutFullScreen(true)})

设置完之后,效果和方式一是一样的。

虽然说解决了间距问题,但是,沉浸式之后,由于不会避让状态栏与导航栏,会出现底部的组件被遮挡的情况,也就是如下图所示:

这种情况下,如果你想实现软键盘弹出后无间距,软键盘收起后,组件在底部导航栏上面,那么就需要代码上的动态设置,两种方式,一种是监听输入框的输入状态变化,另一种是监听软键盘弹出的状态,根据不同的状态,然后给组件设置距离底部的距离即可。

监听输入框的输入状态

全部代码如下,在aboutToAppear方法里,设置沉浸式,获取底部的导航栏高度,在onEditChange方法中,监听输入状态的变化,动态赋值给底部距离属性。

import { window } from '@kit.ArkUI'@Entry
@Component
struct Index {@State marginBottom: number = 0private bottomRectHeight: number = 0 //底部导航栏高度aboutToAppear(): void {window.getLastWindow(getContext(), (_, win) => {win.setWindowLayoutFullScreen(true)let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATORlet avoidArea = win.getWindowAvoidArea(type)// 获取到导航条区域的高度this.bottomRectHeight = px2vp(avoidArea.bottomRect.height)this.marginBottom = this.bottomRectHeight //初始化默认距离底部距离})}build() {Column() {TextInput().margin({ bottom: this.marginBottom }).onEditChange((isEditing: boolean) => {this.marginBottom = isEditing ? 0 : this.bottomRectHeight})}.width("100%").height("100%").justifyContent(FlexAlign.End)}
}

运行之后,可以看到,默认在导航栏上面,软键盘弹起后,也没有任何间距。

监听软键盘弹出状态

无非就是把输入框的输入状态切换为了软键盘的弹出状态。

 // 监听软键盘的隐藏和显示win.on('keyboardHeightChange', (height) => {this.marginBottom = height > 0 ? 0 : this.bottomRectHeight})

按照正常逻辑而言,应该和上面的效果是一样的,但偏偏剑走了弯路,当软键盘弹出后输入框明显被遮挡。

我真实服了这个老六,无非就是换了一个监听方式,怎么还给了一个惊喜呢,针对这种情况,建议直接使用第一种方式,当然了,如果你仍然要用这种方式,也不是不行,软键盘弹出后,需要加上被遮挡的高度,也就是44px。

 // 监听软键盘的隐藏和显示win.on('keyboardHeightChange', (height) => {this.marginBottom = height > 0 ? px2vp(44) : this.bottomRectHeight})

方式三、动态设置位置

所谓的动态设置,就是根据软键盘的高度,动态设置组件的位置,也就是需要获取软键盘的高度,当软键盘弹起时,让组件距离底部的距离正好是软键盘的高度,这种方式和沉浸式布局方式有点类似,但是不需要设置沉浸式。

有一点需要注意,那就是需要配置扩展安全区域的类型为SafeAreaType.KEYBOARD,目的防止组件随着软键盘抬起而置顶。

import { window } from '@kit.ArkUI'@Entry
@Component
struct Index {@State marginBottom: number = 0aboutToAppear(): void {window.getLastWindow(getContext(), (_, win) => {let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATORlet avoidArea = win.getWindowAvoidArea(type)// 获取到导航条区域的高度let bottomRectHeight = px2vp(avoidArea.bottomRect.height)// 监听软键盘的隐藏和显示win.on('keyboardHeightChange', (height) => {this.marginBottom = height > 0 ? px2vp(height) - bottomRectHeight : 0})})}build() {Column() {TextInput().margin({ bottom: this.marginBottom })}.width("100%").height("100%").justifyContent(FlexAlign.End).expandSafeArea([SafeAreaType.KEYBOARD])}
}

以上的代码运行之后,可以发现和上面的效果是一样的,当然了位置,并不一定通过margin,你也可以通过offset属性,或者padding属性等等。

offset({y:-this.marginBottom})

相关总结

还是那句话,自我感觉,鸿蒙系统对于这个间距的处理,我觉得是正常的,毕竟更加符合视觉美观,如果紧挨着展示,反而觉得不太美观;但话又回来,需求是多变的,人无完人,金无足赤,每个产品都有自己的思想,而作为研发的我们,如果你没有反向修改的勇气,那么只管找解决办法即可。

三种方式,比较推荐方式一,简单便捷,一行代码便可以搞定,当然,另外两种也是实现的办法,在实际的开发中,选择适合的即可。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词