HarmonyOS 鸿蒙Next中如何解决Web组件高度无法动态改变的问题
HarmonyOS 鸿蒙Next中如何解决Web组件高度无法动态改变的问题
【问题现象】
在Web组件中,加载了一个包含输入区域的HTML页面,当点击页面中的任何区域,系统输入法弹出之后会通过listenKeyboard
监听到输入法键盘高度,并压缩Web组件的高度,让它缩小到屏幕上半部分。
- 预期效果: 系统输入法弹出后,Web组件的渲染区域缩小到屏幕上半部分,并且在Web组件和输入法之间有预留的动态避让区(通过Blank组件实现)。
- 实际效果: 系统输入法弹出后,虽然组件树中感知到动态避让区(Blank组件)高度为413vp,但实际并没有绘制出动态避让区,且Web组件的渲染区域并未缩小到屏幕上半部分,如下图。
在下面代码片段中,期望通过监听键盘高度来实现Web组件高度动态改变。
问题代码如下:
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';
import { window } from '@kit.ArkUI';
@Entry
@Component
struct WebComponent {
controller: webview.WebviewController = new webview.WebviewController();
@State toolOff: number = 0;
aboutToAppear(): void {
try {
webview.WebviewController.setWebDebuggingAccess(true);
this.listenKeyboard();
} catch (error) {
console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
}
// 监听键盘高度
private listenKeyboard() {
window.getLastWindow(getContext(this)).then(currentWindow => {
// 监听键盘高度,处理工具条偏移量
currentWindow.on('keyboardHeightChange', (data) => {
let keyboardHeight = Math.floor(px2vp(data));
if (keyboardHeight > 0) {
// 键盘编辑态,偏移量 = 键盘高度
this.toolOff = keyboardHeight + 100
} else {
// 无键盘编辑态,安全区高度
this.toolOff = 0
}
})
})
}
build() {
Stack() {
Column() {
Web({ src: $rawfile('index.html'), controller: this.controller })
.onControllerAttached(() => {
// 推荐在此loadUrl、设置自定义用户代理、注入JS对象等
console.log('onControllerAttached excute')
}).layoutWeight(1)
// 编辑态避让区
Blank()
.backgroundColor("00000000")
.width('100%')
.height(this.toolOff)
}
}
}
}
【背景知识】
- 使用Web组件加载页面:页面加载是Web组件的基本功能。根据页面加载数据来源可以分为三种常用场景,包括加载网络页面、加载本地页面、加载HTML格式的富文本数据。
- Web组件大小自适应页面内容布局:使用Web组件大小自适应页面内容布局模式时,能使Web组件的大小根据页面内容自适应变化。
- 安全区域:安全区域是指页面的显示区域,默认不与系统设置的非安全区域比如状态栏、导航栏区域重叠,默认情况下开发者开发的界面都被布局在安全区域内。
【定位思路】
为解决Web组件高度无法改变的问题,可以从组件渲染效果以及安全区域限制方面考虑:
- 排查Blank组件在高度动态修改时的作用
如果Blank组件高度动态修改后只是覆盖上去了,并不是把Web页面顶上去,那么Web页面高度没有变化,导致看到手机上效果和inspector上效果不一致。虽然修改height('calc(100% - 413vp)')
后可以达到理想效果,但是Web组件的高度并不能动态改变。
- 排查是否只是改变Web组件在屏幕上的显示区域
在Web组件上加一个layoutWeight(1)
属性后,虽然会改变当前Web组件在屏幕上的显示区域,但它的高度是不会发生改变的。由于inspector是通过获取组件高度来绘制的,因此layoutWeight(1)
属性没办法修改Web组件的高度,只能修改其在父组件中的布局。可以看到inspector上的Web高度始终没有改变,它的显示区域只是被盖上,并不会动态改变。
- 针对安全区域进行处理
通过排查可以知道,问题代码的处理,并不能使Web组件的高度动态变化。参考背景知识,为了解决这个问题,需要通过突破安全区域的限制来处理。利用安全区域的expandSafeArea属性支持组件不改变布局情况下扩展其绘制区域至安全区外。
【解决方案】
根据定位思路,在Web中添加expandSafeArea([SafeAreaType.KEYBOARD])
,控制组件扩展其安全区域。处理效果如下图,可以看到在键盘上方按照预期成功产生了空白的预留区域,实现了Web组件的高度动态变化。
Web({ src: $rawfile('index.html'), controller: this.controller })
.onControllerAttached(() => {
// 推荐在此loadUrl、设置自定义用户代理、注入JS对象等
console.log('onControllerAttached excute')
}).layoutWeight(1)
.expandSafeArea([SafeAreaType.KEYBOARD])
处理效果:
【总结】
对于组件在页面显示区域内的变化,可以考虑设置组件绘制内容突破安全区域的限制来处理。其中需要注意的几点是:
(1)组件设置expandSafeArea
属性之后生效的条件为:
type
为SafeAreaType.KEYBOARD
时默认生效,组件不避让键盘。- 设置其他
type
,组件的边界与安全区域重合时组件能够延伸到安全区域下。例如:设备顶部状态栏高度100,那么组件在屏幕中的绝对位置需要为0 <= y <= 100。
(2)组件延伸到安全区域下,在安全区域处的事件,如点击事件等可能会被系统拦截,优先给状态栏等系统组件响应。
(3)滚动类容器内的组件不建议设置expandSafeArea
属性,如果设置,需要按照组件嵌套关系,将当前节点到滚动类祖先容器间所有直接节点设置expandSafeArea
属性,否则expandSafeArea
属性在滚动后可能会失效。
(4)除了组件扩展其安全区域外,和键盘相关比较常见的还有setKeyboardAvoidMode - 控制虚拟键盘抬起时页面的避让模式、getKeyboardAvoidMode - 返回虚拟键盘抬起时的页面避让模式。
更多示例请见官方文档安全区域。
更多关于HarmonyOS 鸿蒙Next中如何解决Web组件高度无法动态改变的问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html
更多关于HarmonyOS 鸿蒙Next中如何解决Web组件高度无法动态改变的问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,通过使用expandSafeArea([SafeAreaType.KEYBOARD])
属性,可以使Web组件在键盘弹出时动态调整高度。具体实现如下:
Web({ src: $rawfile('index.html'), controller: this.controller })
.onControllerAttached(() => {
console.log('onControllerAttached excute')
}).layoutWeight(1)
.expandSafeArea([SafeAreaType.KEYBOARD])
此方法使Web组件在键盘弹出时自动调整高度,确保在键盘上方预留出空白区域,实现动态避让效果。