微信小程序自定义navigationBar

这里使用三段论是什么为什么怎么做来阐述自定义navigationBar,如果只关心怎么做可直接跳至怎么做段落。

navigationBar是什么?

  • 微信小程序一般来说有两个bar,一个导航栏,一个tabbar(小程序下方一排切换按钮),实现下方自定义tabbar的方法一般来说较为简单,现在着重叙述上方自定义导航栏的实现。

小程序布局

  • 谈到导航栏与自定义导航栏,就需要解释一下微信小程序的布局了。在小程序开发中使用wx.getSystemInfo() 方法可以获取到系统信息。
wx.getSystemInfo()
image
  • 部分获取到的信息如上图(截取自微信小程序开发者文档),对我们理解布局有用的信息是以上跟宽度高度相关的属性,如当前设备的屏幕高宽,可用高宽,以及saveArea
image
  • 上图展示我们从systemInfo获取到的数据的实际表现,以苹果X的刘海屏为例(所有安卓刘海屏原理类似):最外层的红色框即屏幕大小,蓝色框即安全区域字面意思也就是开发者所能操纵的页面区域,上面的黄色框即手机的状态栏,绿色区域即我们要自定义的navigationBar
  • 可见,导航栏紧贴safeArea的上部,如果使用原生导航栏,导航栏下方即是真正意义的可操控范围。
  • 实际上我们自定义的导航栏也是在这个safeArea内与胶囊对齐最为和谐。很关键的原因就是微信将右上角的胶囊按钮作为了内置组件,只有黑白两种颜色,即我们无法改变它的大小位置透明度等等,所以为了配合胶囊按钮,一般自定义的导航栏位置也与上图位置一致。

为什么要自定义navigationBar?

原生导航栏的限制

  • 除了胶囊按钮以外,原生导航栏只会出现返回按钮和当用户打开的小程序最底层页面是非首页时,默认展示的“返回首页”按钮 。
  • 原生导航栏的标题文字的颜色只有黑白。
  • 布局无法改变,不能做定制。

产品需求

  • 如果说原生导航栏的限制还不足以让你加入自定义导航栏,那么产品需求绝对是更大的推动力。

  • 自定义导航栏除了不能自定义胶囊按钮以外,其他的范围都是程序员的掌控范围,所以使用自定义导航栏无疑可以满足产品的各种需求。

携程navigationBar
斗鱼navigationBar
  • 如果你的产品有上图的需求,显然你不能say no,你只能满足需求,加上自定义navigationBar。

自定义navigationBar怎么做?

去掉原生导航栏。

  1. 将需要自定义navigationBar页面的page.json的navigationBarTitleText去掉。
  2. 加上"navigationStyle":"custom",这样原生的导航栏就已经消失,甚至后退键也不会出现需要自定义。
  3. 另外,早在2016年微信已经开始适配沉浸式状态栏,目前几乎所有的机型里微信都是沉浸式状态栏,也就是说去掉原生导航栏的同时,整个屏幕已经成为可编程区域

计算navigationBarHeight。

  • 原生的胶囊按钮当然存在,那么下一步就需要你去定位出自定义的导航栏高度以及位置。
  • 对于不同的机型,对于不同的系统,状态栏以及胶囊按钮的位置都不确定,所以需要用到一定的计算,从而面对任何机型都可以从容判定。
  1. 使用wx.getSystemInfo()获取到statusBarHeight,这样就确定了导航栏最基本的距离屏幕上方的据里。
  2. 使用wx.getMenuButtonBoundingClientRect()获取到小程序的胶囊信息(注意这个api存在各种问题,在不同端表现不一致,后面会叙述这个api调用失败的处理情况),如下图,以下坐标信息以屏幕左上角为原点。
获取结果
  1. 以下图为例,上面的红色框是statusBar,高度已知;下面的红色框是正文内容,夹在中间的就是求解之一navigationBarHeight;而黄色的是原生胶囊按钮也是在垂直居中位置,高度为胶囊按钮基于左上角的坐标信息已知,不难得出,navigationBarHeight = 蓝色框高度 × 2 + 胶囊按钮.height。(蓝色框高度 = 胶囊按钮.top - statusBarHeight
image
  1. 最后的计算公式为:navigationBarHeight = (胶囊按钮.top - statusBarHeight) × 2 + 胶囊按钮.height。navigationBar 距屏幕上方的距离即为navigationBarHeight

  2. 这种计算方法在各种机型以及安卓ios都适用。

  3. 针对"wx.getMenuButtonBoundingClientRect()"获取错误或者获取数据为0的极少数情况,只能够去模拟,对于android,一般navigationBarHeight为48px,而对于ios一般为40px,所有机型的胶囊按钮高度是32px笔者也是通过网上很多的文章和自测得出的,这种误差一般可以忽略。当然最理想的就是微信可以hold住所有机型,呵呵。最后提醒一下仅以真机为准,开发者工具的bug就更多不说了。

获取失败情况

代码实现

  • 获取本机信息,笔者一般写在App的onLaunch中。

App.js

// App.js
...
onLaunch(){
    const { statusBarHeight, platform } = wx.getSystemInfoSync()
    const { top, height } = wx.getMenuButtonBoundingClientRect()

    // 状态栏高度
    wx.setStorageSync('statusBarHeight', statusBarHeight)
    // 胶囊按钮高度 一般是32 如果获取不到就使用32
    wx.setStorageSync('menuButtonHeight', height ? height : 32)
    
    // 判断胶囊按钮信息是否成功获取
    if (top && top !== 0 && height && height !== 0) {
        const navigationBarHeight = (top - statusBarHeight) * 2 + height
        // 导航栏高度
        wx.setStorageSync('navigationBarHeight', navigationBarHeight)
    } else {
        wx.setStorageSync(
          'navigationBarHeight',
          platform === 'android' ? 48 : 40
        )
    }
}
...
  • 笔者将这几个高度信息储存在stroage中,之后创建navigationBar自定义组件,在组件中将会运用到这些数据。

navigationBar.js

// navigationBar.js
...
data: {
    // 状态栏高度
    statusBarHeight: wx.getStorageSync('statusBarHeight') + 'px',
    // 导航栏高度
    navigationBarHeight: wx.getStorageSync('navigationBarHeight') + 'px',
    // 胶囊按钮高度
    menuButtonHeight: wx.getStorageSync('menuButtonHeight') + 'px',
    // 导航栏和状态栏高度
    navigationBarAndStatusBarHeight:
      wx.getStorageSync('statusBarHeight') +
      wx.getStorageSync('navigationBarHeight') +
      'px'
}
...
  • navigationBar.wxml中的布局就不多赘述,一般来说,导航栏使用fixed定位,里面再通过行内垂直居中的方式定位自定义的返回按钮,还有居中导航标题,以及字数过多显示省略号等。

navigationBar.wxml

<!--navigationBar.wxml-->
<view class="navigation-container" style="{{'height: ' + navigationBarAndStatusBarHeight}}">
    <!--空白来占位状态栏-->
    <view style="{{'height: ' + statusBarHeight}}"></view>
    <!--自定义导航栏-->
    <view class="navigation-bar" style="{{'height:' + navigationBarHeight}}">
        <view class="navigation-buttons" style="{{'height:' + menuButtonHeight}}">
            <image class="nav-img" src='/images/back.svg'/>
            ...其余自定义button
        </view> 
        <view class="navigation-title" style="{{'line-height:' + navigationBarHeight}}">{{title}}</view>
    </view>    
</view>
<!--空白占位fixed空出的位置-->
<view style="{{'height: ' + navigationBarAndStatusBarHeight}}; background: #ffffff"></view>

navigationBar.wxss

/* navigationBar.wxss */
.navigation-container {
  position: fixed;
  width: 100%;
  z-index: 99;
  top: 0;
  left: 0;
  background-color: #ffffff;
}
.navigation-bar {
  position: relative;
  display: flex;
  flex-direction: row;
  align-items: center;
}
.navigation-buttons {
  display: flex;
  align-items: center;
  margin-left: 10px;
  border: 1px solid rgba(0, 0, 0, 0.05);
  box-sizing: border-box;
  border-radius: 15px;
  background-color: transparent;
}
.nav-img{
  height: 16px;
  width: 16px;
}
.navigation-title {
  position: absolute;
  left: 104px;
  right: 104px;
  text-align: center;
  font-size: 16px;
  font-weight: bold;
  color: #000000;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

总结

  • 自定义导航栏核心在于导航栏的高度定位,这样才能准确定位自定义的返回按钮以及其他按钮的位置,与原生胶囊保持一致。至于wxml的布局方法多种多样,上面只是列出了笔者的一种写法。
  • 学习小程序,自定义导航栏是很重要的技能,其间的逻辑并不复杂,还是和学习前端一样,需要非常细心耐心,才能做好细节工作。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • 需求 产品说小程序返回到首页不太方便,想添加返回首页按钮,UI说导航栏能不能设置背景图片,因为那样设计挺好看的。 ...
    一个敲代码的前端妹子阅读 3,146评论 1 4
  • 夕阳无限爱,居家养老行;暖心连百姓,人间有真情。改革开放40年来,随着人口老龄化的加剧和养老事业的稳步发展,宁波国...
    喜欢吃榴莲阅读 421评论 0 0
  • 今天总算人头脑清醒了些,由于这次请了长病假让我感觉到了作为上班族的无力感,于是,我做了两个小小的决定: 1、淘宝买...
    注册营养技师慧恩阅读 186评论 0 1
  • 忙了一天到现在才有空坐下来做点自己想做的事,可是又到即将要睡的时间了,莫名的很思念,莫名的伤感,以及莫名的很想哭。...
    我们的南北阅读 193评论 0 0
  • 自从开展打黑除恶运动以来,足浴店这种明显藏污纳垢的㘯所关掉了,以营利为目的麻将舘也关掉了,但是浴室、舞厅却一直开开...
    自強男儿阅读 421评论 0 6