场景
临近国庆,pm要紧急加一个微信小程序的活动,一周就要上线。于是设计小姐姐们周末连夜加班,为了节约时间,最后甩给我一张375 * 812,基本所有按钮等元素都在图上的图片作为背景。
在活动上线前一天,pm看了之后表示,这个背景图头部太大了,iphone8这种比较“短”的屏幕里可能一半都是头图了。要保证不同尺寸的屏幕,都要能露出活动的核心内容。因为设计小姐姐来不及重新出图,就希望我们可以在头部截掉最多90rpx的部分。
最开始的实现
拿过这个需求,感觉很简单嘛。背景图不适配就只能靠定位了。比较“短”的屏幕就从上面用负数的margin-top截一点,不过为了保证屏幕下方不能出现“白边”,需要用windowHeight计算一下比例。
所以当时的我就是这样写的:
const { windowWidth, windowHeight } = app.$systemInfo;
const clipHeight = Math.min(Math.floor(windowWidth / 375 * 812 - windowHeight), 90);
this.setData({ clipHeight });
其中app.$systemInfo是我们小程序里缓存的系统信息。配合wxml里这样写就实现了这个功能。
<view class="container" style="margin-top: -{{clipHeight}}rpx"></view>
做完这些我还再开发者工具和开发版验证了一下,效果完全符合预期。
问题
临近上线,我们发了一版体验版,发现很多机型屏幕下方并没有撑满,露出来一条“白边”。出问题的机型主要集中在“刘海屏”和“打孔屏”上。
过程【我太蠢了,可以忽略】
很快我们就发现在通过wx.getSystemInfo获取的系统信息,在体验版和开发版上返回的结果居然不一样。(我其实很可以理解开发者工具和真机效果不一样,但是同是真机环境,体验版和开发版的结果为什么会不一样呢。)
然后我们试了一下screenHeight。这个时候下面“白边”虽然缩小了但是还是有“白边”。
又试了一下safeArea.bottom。安卓机完全正常了。但是对于iphonex这种下面带有home indecator的机型,下方依旧会有一个比最开始窄了一些的“白边”。这是因为对于有home indecator的机型,safeArea.bottom会取到home indecator上面。
这个时候我在微信开放社区查了很多相关的问题,发现了wx.getSystemInfo的秘密。
这个窗体高度是你获取手机信息时当前页面的窗体高度,在首页有底部导航栏时,导航栏的高度不计算,所以值会小。
最后在重新调用wx.getSystemInfo的同时,又改回了screenHeight。终于解决了问题。
解决
总结一下。我们遇到了这样两个问题:
wx.getSystemInfo的结果依赖当前页面,tabBar会影响高度计算。screenHeight和windowHeight和safeArea.bottom在体验版和线上版,数值都不同。
而同时这两个问题又都会导致同一个结果,所以也是绕了一圈才解决。
最后结果就是下面这样的,在页面里重新调用wx.getSystemInfoSync获取最新数据,并且用screenHeight替代windowHeight就可以了。
const { screenWidth, screenHeight } = wx.getSystemInfoSync();
const clipHeight = Math.min(Math.floor(screenWidth / 375 * 812 - screenHeight), 90);
this.setData({ clipHeight });