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组件高度无法动态改变的问题,可以尝试以下解决方案:
- 设置layoutMode:确保Web组件使用了
layoutMode(WebLayoutMode.FIT_CONTENT)
,这能使Web组件的大小根据页面内容自适应变化。 - 使用nestedScroll属性:在Scroll组件中嵌套Web组件时,应设置
nestedScroll
属性,并合理配置其滚动行为(如scrollForward
和scrollBackward
),以支持嵌套滚动。 - JavaScript注入:通过
javaScriptOnDocumentStart
注入JavaScript,确保在页面加载完成后执行相关代码,如动态调整Web组件的尺寸。 - 明确宽度设置:宽度设置不明确可能导致Scroll组件的高度无法正确计算,因此需要确保Web组件有明确的宽度设置。
- 检查Web内容:确保加载的HTML内容没有额外的空白区域或未正确关闭的标签,这些都会影响Web组件的高度计算。
此外,如果Web组件加载的是外部网页,还需确保网页已适配鸿蒙系统的用户代理(UA),可通过setCustomUserAgent
方法设置合适的UA字符串。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html 。