Cordova状态栏(cordova-plugin-statusbar)插件的使用,让webapp具有nativeapp的用户体验

4,722 阅读5分钟

一、前言

众所周知,webapp对比nativeapp而言,虽然具有跨平台的优势,但是在用户体验方面却比不上nativeapp,比如如何让webapp具备ios的惯性滚动和边缘回弹,又如如何让webapp具有和原生app一样的状态栏(透明、沉浸式)。对于前者,我采用的是better-scroll(一款重点解决移动端各种滚动场景需求的插件),对于后者,我采用的是Cordova状态栏插件--cordova-plugin-statusbar,因为我所在公司开发的webapp就是用vue进行开发,然后再用Cordova进行打包,这也是本文要和大家分享的内容。

二、正文

  • Cordova-plugin-statusbar 插件的安装和使用
cordova plugin add cordova-plugin-statusbar

安装完插件之后,在cordova工程的config.xml文件里面进行以下配置

<preference name="StatusBarOverlaysWebView" value="true" />
<preference name="StatusBarStyle" value="lightContent" />

StatusBarOverlaysWebView它决定了状态栏是否覆盖webview,值为布尔类型,为true时覆盖,具体表现就是和视图重叠,为false时不覆盖,默认是true。

StatusBarStyle它决定了状态栏的样式,可选值为default,lightcontent, blacktranslucent, blackopaque,值为default时,具体表现为状态栏字体颜色为黑色,而值为lightcontent、blacktranslucent、blackopaque,具体表现一致,状态栏字体颜色为白色。

需要注意的是,这里不需要配置StatusBarBackgroundColor,因为不设置值的时候,状态栏的背景颜色是透明的,也是本文想要达到的效果,可参见以下cordova官方文档

StatusBarBackgroundColor (color hex string, no default value). On iOS, set the background color of the statusbar by a hex string (#RRGGBB) at startup. If this value is not set, the background color will be transparent.

在配置完后进行打包,这里先对ios进行调试,可参见以下效果图,

可以发现,并没有达到我们想要的效果,这看起来就好像是状态栏没有覆盖webview,而是占据着一定的位置,而且从第二张图可以发现固定定位top为0的元素居然是在状态栏的下方而不是和状态栏重叠在一起,这是为什么呢?接下来就要说说ios的状态栏和安全区了。

  • 状态栏和安全区

在早期版本的iOS上,状态栏只是一个固定屏幕上方的黑色条带,并且是不可触摸的。它属于系统UI的一部分,你的app运行在它的下方空间中。随着iOS7的推出,状态栏变成了透明的,它的颜色取自应用程序导航栏的颜色。对于运用在webview中的app比如Cordova,通常要判断iOS的版本然后在固定的导航栏上方预留20px的边距,以便正确的填充导航栏。而对于iOS 11与早期版本的不同在于,webview内容区超出了安全区。这也就是说,如果你有一个头部导航条使用fixed定位元素并且使用top: 0,那么它会在屏幕顶部20px的下方渲染:对齐到状态栏的底部。

既然现在知道了原因,那有没有办法解决呢,答案是当然有,苹果给我们一种方式来控制这种形式,通过meta标签。更幸运的是,这种新的视口行为也适用于老的版本,包括弃用的UIWebView,这个视口选项就是viewport-fit!

所以我们只要在index.html的meta标签加上viewport-fit=cover,并且预留出20px或着更多的高度(具体可自由调整,但不低于20px)给状态栏即可。

关于更多状态栏和安全区的具体内容可参见cordova iOS11 webView适配(转)

接下来继续打包调试,效果图如下

现在已经达到我们想要的效果了,但是完了吗?其实并没有,因为上图中状态栏的字体颜色是白的的,背景图片是深色的,但是如果遇到背景色也是白色的视图,那么状态栏就会看不见了,所以接下来就是根据路由或者通过事件动态改变状态栏的样式,

这里就要用到StatusBar.styleLightContent()和StatusBar.styleDefault()这两个方法了。

在app.vue文件里面侦听路由

methods: {
    onDeviceReady () {
        // 根据路由动态改变状态栏样式
        // 我给状态栏字体色为白色的路由都设置了一个路由元meta,属性statusBgc为1
        this.$route.meta.statusBgc ? StatusBar.styleLightContent() : StatusBar.styleDefault()
    }
},
watch: {
    $route (to, from) {
        // cordova插件会定义一个StatusBar对象,当它只能在deviceready后才能使用
        document.addEventListener("deviceready", this.onDeviceReady, false)
    }
  }
  • iphoneX的适配

由于iphoneX齐刘海的设计,之前预留出的20px仍会导致视图会被刘海锁覆盖,不过好在苹果添加了一种方法,将安全区域布局指南暴露给CSS。他们添加类似一个CSS的变量概念,叫作CSS constant。可以考虑这样的CSS变量,这些变量是由系统设计的,不能被覆盖。它们可以通过CSS的constant()函数来完成。

所以只要加上

padding: constant(safe-area-inset-top) constant(safe-area-inset-right) constant(safe-area-inset-bottom) constant(safe-area-inset-left);  

constant(safe-area-inset-top):在Viewport顶部的安全区域内设置量(CSS像素) constant(safe-area-inset-bottom):在Viewport底部的安全区域内设置量(CSS像素) constant(safe-area-inset-left):在Viewport左边的安全区域内设置量(CSS像素) constant(safe-area-inset-right):在Viewport右边的安全区域内设置量(CSS像素)

  • 安卓的适配

在ios调试完了之后,我发现

<preference name="StatusBarOverlaysWebView" value="true" />
<preference name="StatusBarStyle" value="lightContent" />

这两配置在安卓好像并不起作用,具体表现就是状态栏不覆盖webview而且背景色是黑色的,后来看了下cordova文档发现安卓需要使用StatusBar.overlaysWebView(true)这个方法。对之前的app.vue进行修改如下:

methods: {
    onDeviceReady () {
        // 根据路由动态改变状态栏样式
        // 我给状态栏字体色为白色的路由都设置了一个路由元meta,属性statusBgc为1
        this.$route.meta.statusBgc ? StatusBar.styleLightContent() : StatusBar.styleDefault()
    }
},
watch: {
    $route (to, from) {
        // cordova插件会定义一个StatusBar对象,当它只能在deviceready后才能使用
        if (cordova.platformId == 'android') { // 安卓需要特殊处理,参见 cordova 官方文档
        StatusBar.overlaysWebView(true)
      }
        document.addEventListener("deviceready", this.onDeviceReady, false)
    }
  },
created () {
    // 保证安卓第一次进入状态栏能覆盖webview
    document.addEventListener("deviceready", this.onDeviceReady, false)
  }

三、结束语

好啦,以上就是本文所要分享的全部内容,感谢阅读~

四、参见

cordova-plugin-statusbar

cordova iOS11 webView适配(转)

iPhone X的缺口和CSS