UI 适配的暗礁,沉浸式状态栏、安全区与软键盘交互重构
前两天 UI 设计师在群里大发雷霆,说我做出来的页面在真机上全乱套了。仔细一看确实惨不忍睹:顶部的背景图被状态栏的电池电量遮挡,底部的输入框在弹出软键盘后被顶飞到了屏幕之外,还有侧边的返回手势和页面里的侧滑控件严重冲突。这三大顽疾,是每个鸿蒙开发者都必须跨过的深水区。
处理状态栏与导航栏
要想页面全屏沉浸,首先得在 EntryAbility 里把系统栏设为透明。
typescript
import window from '@ohos.window';
onWindowStageCreate(windowStage: window.WindowStage) {
windowStage.getMainWindow().then((win) => {
// 设置全屏布局
win.setWindowLayoutFullScreen(true);
// 将状态栏和导航栏设置为透明
win.setWindowSystemBarProperties({
statusBarColor: '#00000000',
navigationBarColor: '#00000000',
statusBarContentColor: '#FFFFFF',
navigationBarContentColor: '#FFFFFF'
});
});
}
但此时,你的页面内容会直接顶到屏幕最上方,被前置摄像头区域遮挡。必须获取系统栏的避让高度(AvoidArea),动态给页面加上 padding。
typescript
// 获取顶部安全区高度 let avoidArea = win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); let topHeight = px2vp(avoidArea.topRect.height); // 将 topHeight 应用到页面的 padding-top 上
极其容易忽略的警示:在折叠屏展开或者横竖屏切换时,安全区的高度是动态变化的。必须监听 win.on('avoidAreaChange') 事件,实时更新你的 padding 值。
软键盘防顶起的降维打击
这是引发用户差评最多的雷区。默认情况下,软键盘弹出会把整个页面往上推。如果你的页面里有一个长列表,整个列表会瞬间被压缩,体验极差。
必须干预系统的键盘避让模式。在 windowStage 加载完成后,设置键盘模式为 RESIZE。
typescript
win.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE);
设置之后,键盘弹出只会压缩当前窗口的高度,而不会平移整个页面。接着,你需要配合 Scroll 组件,并给输入框加上 scrollIntoView 的逻辑。当用户点击输入框时,代码自动把输入框滚动到键盘上方的可视区域内,而不是傻等系统去推它。
手势冲突的精准拦截
最后是侧滑返回的问题。鸿蒙系统有左右边缘侧滑返回的手势。如果你的页面里恰好有一个从侧边滑出的抽屉菜单(Drawer),这两者会直接打架。
解决方法是使用 .gesture() 的优先级控制。在抽屉组件上加上 PanGesture,并在 onActionStart 时,立即通过 event.stopPropagation() 阻止事件向上冒泡到系统的侧滑返回。
如果系统的侧滑依然生效,说明底层的窗口拦截了事件。这时候必须在页面的 onBackPress 生命周期里,拦截返回事件,并判断抽屉是否处于打开状态:
typescript
onBackPress() {
if (this.isDrawerOpen) {
// 如果抽屉开着,先关抽屉,不退出页面
this.isDrawerOpen = false;
return true;
}
return false; // 抽屉关着,交给系统处理返回
}
写一个包含图文长列表的聊天页面,底部放一个输入框。将状态栏设为沉浸式,并获取安全区高度。用代码把键盘模式改为 RESIZE。在真机上测试:滑动列表,点击底部输入框,看看输入框会不会被键盘遮挡。如果页面没有明显的抖动跳跃,说明你的避让逻辑完全达标了。
更多推荐
所有评论(0)