沉浸式,状态栏高度,刘海屏怎么开启,适配

沉浸式,状态栏高度,刘海屏怎么开启,怎么适配?看这!
何为沉浸式?

沉浸式就是app的头部和状态栏和何为一体的,webview即为整个手机的高度

何为状态栏?

状态栏就是手机顶部,显示时间电量那一行

除此还有刘海屏,水滴屏,挖孔屏,全面屏,非刘海屏,不同手机状态栏高度又不太一样,需要我们去适配,有一个段子说,如果看到那个手机适配有问题,赶紧把那个手机藏起来,不要让测试发现了。

我们用HBuilder创建的应用默认是不开启沉浸式的,需要我们手动如下配置开启。

打开应用的manifest.json文件,切换到代码视图,在plus -> statusbar 下添加immersed节点并设置值为true。

"plus": {
    "statusbar": {
        "immersed": true
    }
}

由于各系统版本的限制,沉浸式状态栏对系统有要求(Android4.4及以上、iOS7.0及以上,这部分手机应该早已淘汰),如果要兼容各系统版本,需要动态判断当前环境是否支持沉浸式状态栏以及系统状态栏的高度:

使用5+API

判断当前环境是否支持沉浸式状态栏
plus.navigator.isImmersedStatusbar()
如果当前支持沉浸式状态栏则返回true,否则返回false。
获取当前系统状态栏高度
plus.navigator.getStatusbarHeight()
获取系统状态栏高度,Number类型。
其单位是逻辑像素值,即css中可直接使用的像素值,可能存在小数点
但是5+API需要在plusready事件后才能调用,通常此事件在DOM加载渲染后才会触发,无法再渲染前根据不同的状态来设置css。所以会导致位置的一个闪动。

为了解决此问题,在支持5+API运行环境的userAgent中特定字段Html5Plus/1.0后添加Immersed标识,如下:
“Html5Plus/1.0 (Immersed/30)”
其中Immersed/后的30表示状态栏的高度,单位为逻辑像素值。

可以使用正则表达式进行获取:

var immersed = 0;  
var ms=(/Html5Plus\/.+\s\(.*(Immersed\/(\d+\.?\d*).*)\)/gi).exec(navigator.userAgent);  
if(ms&&ms.length>=3){ // 当前环境为沉浸式状态栏模式  
    immersed=parseFloat(ms[2]);// 获取状态栏的高度  
}

开启了沉浸式,页面就会往上移,头部和状态栏重合,所以我们设置界面头区域的顶部内边距为状态栏的高度

var t=document.getElementById(‘header’);
t&&t.style.paddingTop=immersed+‘px’;
不管是ios还是安卓,不管是刘海屏还是非刘海屏,都不用单独去设置了,在公共js里设置好头部即可。

你学会了吗?赶紧新建一个项目试试吧。

H5在全屏Webview中双端适配刘海屏

这种的话一般是封装一个Webview包含返回+标题+分享功能,然后加载H5即可,返回即关闭Webview,标题是读取网页的Title属性,分享是调起客户端的分享弹窗。

然是这次的H5有点不寻常的东西:

导航栏除了返回键、title、右侧的操作菜单(进入另一个H5页),在title还有一个操作项❔,用于点击弹出说明框。
有一个穿透状态栏和导航栏的背景

最终决定采用全屏Webview的形式,整个页面交给H5控制,这样不管页面设计成什么样都能实现,什么全屏背景,设么导航啦加各种东西通通不在话下。于是愉快的开发开始了。

然鹅在打码到一半的时候我意识到一个问题:双端的状态栏高度不一致,并且现在还有刘海屏存在🌚 这可肿么办?

一、IOS适配
首先对于IOS来说,乔帮主整的还是比较规范的,毕竟IOS闭源系统只能跑在Apple硬件上,设备型号有限,已知各机型尺寸如下:

注: 这里获取到的px值跟web中的px虽然单位一样,但并不是我们需要的值!!!Web所需的px实际为IOS中的pt值…,px转pt需要根据设备的ppi(Pixels Per Inch: 像素密度)进行转换:

px: pixel 像素,是屏幕上的显示的基本点,他并不是长度单位,这个点可以很大,也可以很小。点小的话就很清晰,我们称之为“分辨率高”,反之就是“分辨率低”。所以像素是一个相对单位。

pt: point 准确的说法是一个专用印刷单位“镑”,大小为1/72英寸,是一个长度单位。也是绝对长度。

可以看到ios中的px转pt根据设备的ppi大概是3:1/2:1/1:1转换。
转换完可以看到:

4.7寸6、6s、7、8,状态栏高度为20pt,导航栏高度为44pt.
5.5寸的6p、6sp、7p、8p,状态栏高度为18pt,导航栏高度为44pt.
拥有刘海屏的X、XR、XS、XS MAX、11等一系列刘海屏,状态栏高度为44pt,导航栏高度为44pt.
不难发现:

导航栏 高度所有机型都为44pt;
状态栏 高度大致可以根据是否为刘海屏分为两类。没有刘海屏的大小机型分别为18和20pt,可以近似的看成都是20pt来处理,问题不大,有刘海屏的则统一为44pt高,跟导航栏高度相同。
适配方案:
iOS端的适配方案有两种:Apple官方适配方案、机型区分适配、jsBridge方案

Apple官方适配方案:
1、在粪叉之后引入了一个新概念:“safe area(安全区域)”,安全区域指屏幕内不受圆角、齐刘海、底部小黑条等元素影响的可视窗口。如下图:

2、同时,从iOS11开始,为了适配刘海屏,Apple公司对HTML的viewport meta标签做了扩展

viewport-fit=cover可设置为auto, contain, cover三种状态,这里我们重点使用cover值,指页面完全充满屏幕。

3、iOS11同时新增了一个特性,constant(safe-area-inset-*),这是Webkit的一个CSS函数,用于获取安全区域与边界的距离,有四个预定义的变量(单位px):

safe-area-inset-left:安全区域距离左边界距离,横屏时适配
safe-area-inset-right:安全区域距离右边界距离,横屏时适配
safe-area-inset-top:安全区域距离顶部边界距离,竖屏下刘海屏为44px,iphone6系列20px,竖屏刘海适配关键
safe-area-inset-bottom:安全区域距离底部边界距离,竖屏下为34px,竖屏小黑条适配关键
这样适配方案就比较明确了:

首先通过设置让页面充满全屏
通过Webkit内置的CSS函数,获取安全区域与各边之间的间距,然后通过padding/margin/绝对定位等方式,让页面元素展示在安全区域内。
注: Webkit在iOS11中新增CSS Functions: env( )替代constant( ),文档中推荐使用env( ),而 constant( ) 从Safari Techology Preview 41 和iOS11.2 Beta开始会被弃用。在不支持env( )的浏览器中,会自动忽略这一样式规则,不影响网页正常的渲染。为了达到最大兼容目的,我们可以 constant( ) 和 env( ) 同时使用。

padding-top: constant(safe-area-inset-top); /* iOS 11.0 */
padding-top: env(safe-area-inset-top); /* iOS 11.2 */

最终适配代码如下:

使用@supports查询机型是否支持constant() / env()实现兼容代码隔离,个别安卓也会成功进入这个判断,因此加上-webkit-overflow-scrolling: touch的判断可以有效规避安卓机。

@supports ((height: constant(safe-area-inset-top)) or (height: env(safe-area-inset-top))) and (-webkit-overflow-scrolling: touch) {
  .fullscreen {
    /* 适配齐刘海 */
    padding-top: 20;
    padding-top: constant(safe-area-inset-top);
    padding-top: env(safe-area-inset-top);
    
    /* 适配底部小黑条 */
    padding-bottom: 0;
    padding-bottom: costant(safe-area-inset-bottom);
    padding-bottom: env(safe-area-inset-bottom);
  }
}

机型区分适配
这个就比较简单粗暴无脑了。因为目前市面上已有的Apple手机尺寸我们都是已知的,那剩下的就是css中的media适配了:

/* iphone x / xs / 11 pro*/
@media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) {
  ...
}
/* iphone xr / 11 */
@media only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) {
  ...
}
/* iphone xs max / 11 pro max */
@media only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) {
  ...
}

emmmmmm… 工作量大了点,另外每年9月份发布会后要及时更新代码🙈

jsBridge方案
如果你跟客户端小哥哥的关系比较好的话,就用这种方案吧😳,让客户端写个方法获取状态栏高度,然后在页面加载的时候通过jsbridge调用获取到状态栏高度,然后设置页面样式即可。

好了,鄙人想到的iOS适配方案到此为止。

二、Android适配方案
整完相对规范的iOS,开源的Android就相当眼花缭乱了,机器厂商百花齐放,各厂商的机型也是眼花缭乱。Android机型成百上千,适配方案反而变的简单了!!!why? 因为只有一种方案:JSBridge

像上述iOS的适配方案中,官方适配方案Android肯定是么得了,毕竟机型太多,搞不了官方规范。其次就是CSS media 查询精准适配,如果你的应用只针对于少数机型,那这种方案还是可以用用的,倘若不是那就拜拜了您嘞。

jsBridge方案
同iOS,客户端获取状态栏高度后,H5通过JSBridge交互拿到状态栏高度,设置页面样式避开齐刘海区域。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章