ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

iPhone 14 Pro 把导航栏顶歪了?job-uniapp 自定义导航栏高度计算与胶囊坐标公式

iPhone 14 Pro 把导航栏顶歪了?job-uniapp 自定义导航栏高度计算与胶囊坐标公式 uniapp 自定义导航栏总对不齐状态栏高度 胶囊按钮坐标刘海屏适配我踩的 5 个坑做小程序最烦的就是导航栏。默认导航栏丑、样式定制弱想做成品牌色 自定义按钮只能关掉默认导航栏自己画。自己画就躲不开一个问题不同机型的状态栏高度不一样胶囊按钮位置也不一样。iPhone 14 Pro 和红米 K60 的刘海/挖孔都不一样写死 64px 是必翻车。job-uniapp 里这套customNavHeight.js折腾了五轮把能踩的坑都踩了。先拿系统信息状态栏高度不能写死uni.getSystemInfoSync()能拿到statusBarHeight这是最基础的参数。注意某些安卓机型第一次调用可能返回 0要在onLaunch里拿一次存起来letcachednull;exportfunctiongetStatusBarHeight(){if(cached!null)returncached;try{constinfouni.getSystemInfoSync();cachedinfo.statusBarHeight||0;}catch(e){cached0;}returncached;}缓存起来的原因是getSystemInfoSync有性能开销而且页面初始化时多次调用结果可能不一致。0 兜底是必须的——万一真拿不到导航栏内容也不能挤到状态栏下面去后面还要处理。胶囊按钮坐标对齐的基准小程序右上角那个胶囊按钮… 和 ○uni.getMenuButtonBoundingClientRect()能拿到它的精确坐标。胶囊底部就是导航栏内容的对齐基准exportfunctiongetNavBarHeight(){conststatusBarHeightgetStatusBarHeight();letmenuRectnull;try{menuRectuni.getMenuButtonBoundingClientRect();}catch(e){menuRectnull;}if(menuRectmenuRect.height){// 胶囊高度 上下边距导航栏内容区高度constcapsuleTopmenuRect.top-statusBarHeight;constnavContentHeightmenuRect.height(capsuleTop*2);return{statusBarHeight,navContentHeight,navTotalHeight:statusBarHeightnavContentHeight,menuRect,};}// 拿不到胶囊比如某些 web 环境就按经验值兜底return{statusBarHeight,navContentHeight:44,navTotalHeight:statusBarHeight44,menuRect:null,};}关键公式navContentHeight 胶囊高度 (胶囊上边距 × 2)。因为胶囊在状态栏和内容之间垂直居中上下边距相等导航栏内容区高度就能算出来。总高度 状态栏 内容区。页面里怎么用CSS 变量注入算出来的尺寸要通过 CSS 变量传给页面别在页面里再调一次 APIexportfunctionapplyNavBarStyle(){constnavgetNavBarHeight();conststyle{--status-bar-height:nav.statusBarHeightpx,--nav-content-height:nav.navContentHeightpx,--nav-total-height:nav.navTotalHeightpx,};Object.keys(style).forEach((key){uni.setStorageSync(navStyle,style);});returnstyle;}页面模板里岗位详情标题文字用绝对定位居中对齐左右按钮分别跟胶囊对齐——左按钮left: 胶囊左边界右按钮right: 屏幕宽度 - 胶囊右边界保证自定义按钮和系统胶囊视觉上在一根线上。踩坑 1Android 首次返回 statusBarHeight 0问题现象部分安卓机主要是小米和 vivo 的某些版本onLaunch里getSystemInfoSync().statusBarHeight返回 0导航栏内容直接顶到最顶上跟时间电量重叠。排查过程加日志打所有机型的状态栏高度发现小米 14 上首次调用返回 0第二次调用返回 61。查社区这是已知的 uniapp 机型适配问题首次同步调用时机太早系统信息还没就绪。定位思路不是 API 不存在是调用时机问题。onLaunch 阶段部分安卓系统信息未就绪返回 0 是假值。最终解决onLaunch里拿不到就延迟重试用setTimeout500ms 后再拿一次页面渲染导航栏前再兜底一次。最终统一走getNavBarHeight()页面渲染时几乎都能拿到正确值。兜底 0 只在最极端情况触发。踩坑 2自定义组件里取不到胶囊坐标问题现象把导航栏封装成自定义组件后组件mounted里调getMenuButtonBoundingClientRect()返回 null导航栏高度算成 44px 兜底跟系统胶囊对不齐。排查过程在组件内外分别打日志发现页面生命周期里能拿到组件 created/mounted 里拿不到。原因是胶囊坐标 API 依赖页面环境组件挂载时机比页面环境初始化早。定位思路导航栏尺寸计算必须放到页面层做算好传进组件不能依赖组件自己调。最终解决applyNavBarStyle()在页面onLoad调用结果存 store/globalData组件computed里读取。从此组件只消费不计算。踩坑 3刘海屏和灵动岛胶囊位置不是固定的问题现象iPhone 14 Pro 灵动岛出来后测试反馈首页和详情页的导航栏高度差了 4px左右按钮跟胶囊不在一条线上。对比 iPhone 13刘海屏胶囊的 top 值确实变了。排查过程把两台真机的getMenuButtonBoundingClientRect()打出来对比iPhone 14 Pro 的胶囊top比 iPhone 13 高了约 4px而且状态栏高度相同。说明灵动岛机型的胶囊视觉位置做了上移跟刘海屏不是同一套坐标。定位思路不能假设同状态栏高度 同胶囊位置胶囊坐标必须每台真机实时拿不能拿一次缓存死。最终解决删掉胶囊坐标缓存逻辑胶囊 rect 每次getNavBarHeight()都实时取状态栏高度可以缓存但胶囊坐标必须现算。改完两台机型对齐。教训苹果改机型设计你就要改适配逻辑这个逃不掉。直接抄走的清单高度公式导航栏总高 状态栏高 胶囊高 2 × 胶囊上边距别写死。拿一次缓存状态栏高度 onLaunch 拿一次存全局别页面级重复调。页面层计算组件层消费胶囊坐标在页面生命周期拿传组件。CSS 变量传递尺寸用 CSS 变量页面样式统一引用。Android 兜底首次 0 就延迟重试最终渲染前再兜底一次。对齐基准自定义按钮左右边界对齐胶囊左右边界视觉才统一。项目源码https://gitee.com/gzqkl/job-uniapp
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进