寻求更优手机刘海屏检测方案:现有iOS检测方法偶现失效
核心问题定位
你现有代码存在两个致命缺陷,是概率性检测失效的根本原因:
- 异步返回值丢失:
setTimeout回调内的return不会作为hasNotch函数的返回值,直接调用hasNotch()拿到的永远是undefined,赋值给$rootScope.hasNotch后控制器判断undefined == true自然为false,只有极偶然的时序巧合下才能碰对结果,刚好对应你说的20%成功率的情况。 - 固定100ms延迟不可靠:不同设备DOM渲染速度差异极大,固定延迟无法保证样式计算完成。
修复现有JS检测逻辑
第一步:改造hasNotch为异步Promise函数
用requestAnimationFrame代替固定延迟,保证浏览器完成样式计算后再取值,同时用Promise处理异步返回:
function hasNotch() { return new Promise((resolve) => { if (!CSS.supports('padding-bottom: env(safe-area-inset-bottom)')) { errMgmt("preIndex/hasNotch ",101.3,"READY: Notch Not Supported") ; return resolve(false); } const div = document.createElement('div'); // 给检测元素加固定定位,避免受页面其他样式影响 div.style.cssText = 'padding-bottom: env(safe-area-inset-bottom); position: fixed; left: 0; bottom: 0; z-index: -9999; visibility: hidden;'; document.body.appendChild(div); // 双raf确保样式更新完成,比setTimeout可靠性高100% requestAnimationFrame(() => { requestAnimationFrame(() => { const calculatedPadding = parseInt(window.getComputedStyle(div).paddingBottom, 10); document.body.removeChild(div); const res = calculatedPadding > 0; res ? errMgmt("preIndex/hasNotch ",101.1,"READY: Notch Detected") : errMgmt("preIndex/hasNotch ",101.2,"READY: Notch Not Detected"); resolve(res); }); }); }); }
第二步:修改赋值逻辑
拿到检测结果后手动触发脏检查更新scope值:
$ionicPlatform.ready(function() { hasNotch().then(res => { $rootScope.$apply(() => { $rootScope.hasNotch = res; }); }); // ...其他原有逻辑 }) ;
第三步:控制器适配异步更新
因为控制器可能早于检测完成初始化,不要直接在初始化时做if判断,用$watch监听值变化:
.controller('HomeCtrl', function($rootScope,$scope,$state,$stateParams,$ionicModal,$q,apiService) { const unwatch = $scope.$watch('$root.hasNotch', function(newVal) { if (newVal === true) { // 执行你的css相关逻辑 unwatch(); // 执行一次后取消监听,避免重复执行 } }); }) ;
更稳定的跨平台通用适配方案
90%以上的刘海适配场景不需要JS参与,直接用CSS原生语法适配即可,完全规避时序问题,同时兼容iOS和安卓9+所有刘海设备:
/* 需要适配刘海底部的元素直接写该样式,无刘海设备env取值为0,自动降级 */ .bottom-action-bar { padding-bottom: calc(16px + env(safe-area-inset-bottom, 0)); } /* 需要适配顶部刘海的元素同理 */ .top-nav-bar { padding-top: calc(12px + env(safe-area-inset-top, 0)); }
如果确实需要JS拿到刘海状态做业务逻辑,可以在之前的检测函数中加入安卓兜底逻辑,覆盖更低版本的安卓设备:
// 安卓厂商刘海兜底检测,可根据需求补充更多厂商适配规则 function checkAndroidNotchFallback() { try { // 安卓9+原生接口判断 const cutout = window.document?.documentElement?.style?.displayCutout; if (cutout) return true; // 屏幕比例兜底,刘海屏设备比例大多≥19.5:9 const screenRatio = Math.max(window.screen.height, window.screen.width) / Math.min(window.screen.height, window.screen.width); return screenRatio >= 1.95; } catch(e) { return false; } }
内容的提问来源于stack exchange,提问作者rolinger
相关产品推荐
相关产品推荐

