微信小程序自定義navigationBar

這里使用三段論是什么為什么怎么做來闡述自定義navigationBar,如果只關(guān)心怎么做可直接跳至怎么做段落莺戒。

navigationBar是什么?

  • 微信小程序一般來說有兩個bar害幅,一個導(dǎo)航欄赃绊,一個tabbar(小程序下方一排切換按鈕),實(shí)現(xiàn)下方自定義tabbar的方法一般來說較為簡單守问,現(xiàn)在著重敘述上方自定義導(dǎo)航欄的實(shí)現(xiàn)匀归。

小程序布局

  • 談到導(dǎo)航欄與自定義導(dǎo)航欄,就需要解釋一下微信小程序的布局了耗帕。在小程序開發(fā)中使用wx.getSystemInfo() 方法可以獲取到系統(tǒng)信息穆端。
wx.getSystemInfo()
image
  • 部分獲取到的信息如上圖(截取自微信小程序開發(fā)者文檔),對我們理解布局有用的信息是以上跟寬度高度相關(guān)的屬性仿便,如當(dāng)前設(shè)備的屏幕高寬体啰,可用高寬攒巍,以及saveArea
image
  • 上圖展示我們從systemInfo獲取到的數(shù)據(jù)的實(shí)際表現(xiàn)荒勇,以蘋果X的劉海屏為例(所有安卓劉海屏原理類似):最外層的紅色框即屏幕大小柒莉,藍(lán)色框即安全區(qū)域字面意思也就是開發(fā)者所能操縱的頁面區(qū)域,上面的黃色框即手機(jī)的狀態(tài)欄沽翔,綠色區(qū)域即我們要自定義的navigationBar兢孝。
  • 可見,導(dǎo)航欄緊貼safeArea的上部仅偎,如果使用原生導(dǎo)航欄跨蟹,導(dǎo)航欄下方即是真正意義的可操控范圍。
  • 實(shí)際上我們自定義的導(dǎo)航欄也是在這個safeArea內(nèi)與膠囊對齊最為和諧哨颂。很關(guān)鍵的原因就是微信將右上角的膠囊按鈕作為了內(nèi)置組件喷市,只有黑白兩種顏色相种,即我們無法改變它的大小位置透明度等等威恼,所以為了配合膠囊按鈕,一般自定義的導(dǎo)航欄位置也與上圖位置一致寝并。

為什么要自定義navigationBar箫措?

原生導(dǎo)航欄的限制

  • 除了膠囊按鈕以外,原生導(dǎo)航欄只會出現(xiàn)返回按鈕和當(dāng)用戶打開的小程序最底層頁面是非首頁時衬潦,默認(rèn)展示的“返回首頁”按鈕 斤蔓。
  • 原生導(dǎo)航欄的標(biāo)題文字的顏色只有黑白。
  • 布局無法改變镀岛,不能做定制弦牡。

產(chǎn)品需求

  • 如果說原生導(dǎo)航欄的限制還不足以讓你加入自定義導(dǎo)航欄,那么產(chǎn)品需求絕對是更大的推動力漂羊。

  • 自定義導(dǎo)航欄除了不能自定義膠囊按鈕以外驾锰,其他的范圍都是程序員的掌控范圍,所以使用自定義導(dǎo)航欄無疑可以滿足產(chǎn)品的各種需求走越。

攜程navigationBar
斗魚navigationBar
  • 如果你的產(chǎn)品有上圖的需求椭豫,顯然你不能say no,你只能滿足需求旨指,加上自定義navigationBar赏酥。

自定義navigationBar怎么做?

去掉原生導(dǎo)航欄谆构。

  1. 將需要自定義navigationBar頁面的page.json的navigationBarTitleText去掉裸扶。
  2. 加上"navigationStyle":"custom",這樣原生的導(dǎo)航欄就已經(jīng)消失搬素,甚至后退鍵也不會出現(xiàn)需要自定義呵晨。
  3. 另外瞬项,早在2016年微信已經(jīng)開始適配沉浸式狀態(tài)欄,目前幾乎所有的機(jī)型里微信都是沉浸式狀態(tài)欄何荚,也就是說去掉原生導(dǎo)航欄的同時囱淋,整個屏幕已經(jīng)成為可編程區(qū)域

計算navigationBarHeight餐塘。

  • 原生的膠囊按鈕當(dāng)然存在妥衣,那么下一步就需要你去定位出自定義的導(dǎo)航欄高度以及位置。
  • 對于不同的機(jī)型戒傻,對于不同的系統(tǒng)税手,狀態(tài)欄以及膠囊按鈕的位置都不確定,所以需要用到一定的計算需纳,從而面對任何機(jī)型都可以從容判定芦倒。
  1. 使用wx.getSystemInfo()獲取到statusBarHeight,這樣就確定了導(dǎo)航欄最基本的距離屏幕上方的據(jù)里不翩。
  2. 使用wx.getMenuButtonBoundingClientRect()獲取到小程序的膠囊信息(注意這個api存在各種問題兵扬,在不同端表現(xiàn)不一致,后面會敘述這個api調(diào)用失敗的處理情況)口蝠,如下圖器钟,以下坐標(biāo)信息以屏幕左上角為原點(diǎn)。
獲取結(jié)果
  1. 以下圖為例妙蔗,上面的紅色框是statusBar傲霸,高度已知;下面的紅色框是正文內(nèi)容眉反,夾在中間的就是求解之一navigationBarHeight昙啄;而黃色的是原生膠囊按鈕也是在垂直居中位置,高度為膠囊按鈕基于左上角的坐標(biāo)信息已知寸五,不難得出梳凛,navigationBarHeight = 藍(lán)色框高度 × 2 + 膠囊按鈕.height。(藍(lán)色框高度 = 膠囊按鈕.top - statusBarHeight
image
  1. 最后的計算公式為:navigationBarHeight = (膠囊按鈕.top - statusBarHeight) × 2 + 膠囊按鈕.height播歼。navigationBar 距屏幕上方的距離即為navigationBarHeight伶跷。

  2. 這種計算方法在各種機(jī)型以及安卓ios都適用。

  3. 針對"wx.getMenuButtonBoundingClientRect()"獲取錯誤或者獲取數(shù)據(jù)為0的極少數(shù)情況秘狞,只能夠去模擬叭莫,對于android,一般navigationBarHeight為48px烁试,而對于ios一般為40px雇初,所有機(jī)型的膠囊按鈕高度是32px筆者也是通過網(wǎng)上很多的文章和自測得出的,這種誤差一般可以忽略减响。當(dāng)然最理想的就是微信可以hold住所有機(jī)型靖诗,呵呵郭怪。最后提醒一下僅以真機(jī)為準(zhǔn),開發(fā)者工具的bug就更多不說了刊橘。

獲取失敗情況

代碼實(shí)現(xiàn)

  • 獲取本機(jī)信息鄙才,筆者一般寫在App的onLaunch中。

App.js

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

    // 狀態(tài)欄高度
    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
        // 導(dǎo)航欄高度
        wx.setStorageSync('navigationBarHeight', navigationBarHeight)
    } else {
        wx.setStorageSync(
          'navigationBarHeight',
          platform === 'android' ? 48 : 40
        )
    }
}
...
  • 筆者將這幾個高度信息儲存在stroage中促绵,之后創(chuàng)建navigationBar自定義組件攒庵,在組件中將會運(yùn)用到這些數(shù)據(jù)。

navigationBar.js

// navigationBar.js
...
data: {
    // 狀態(tài)欄高度
    statusBarHeight: wx.getStorageSync('statusBarHeight') + 'px',
    // 導(dǎo)航欄高度
    navigationBarHeight: wx.getStorageSync('navigationBarHeight') + 'px',
    // 膠囊按鈕高度
    menuButtonHeight: wx.getStorageSync('menuButtonHeight') + 'px',
    // 導(dǎo)航欄和狀態(tài)欄高度
    navigationBarAndStatusBarHeight:
      wx.getStorageSync('statusBarHeight') +
      wx.getStorageSync('navigationBarHeight') +
      'px'
}
...
  • navigationBar.wxml中的布局就不多贅述败晴,一般來說浓冒,導(dǎo)航欄使用fixed定位,里面再通過行內(nèi)垂直居中的方式定位自定義的返回按鈕尖坤,還有居中導(dǎo)航標(biāo)題稳懒,以及字?jǐn)?shù)過多顯示省略號等。

navigationBar.wxml

<!--navigationBar.wxml-->
<view class="navigation-container" style="{{'height: ' + navigationBarAndStatusBarHeight}}">
    <!--空白來占位狀態(tài)欄-->
    <view style="{{'height: ' + statusBarHeight}}"></view>
    <!--自定義導(dǎo)航欄-->
    <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;
}

總結(jié)

  • 自定義導(dǎo)航欄核心在于導(dǎo)航欄的高度定位慢味,這樣才能準(zhǔn)確定位自定義的返回按鈕以及其他按鈕的位置场梆,與原生膠囊保持一致。至于wxml的布局方法多種多樣贮缕,上面只是列出了筆者的一種寫法辙谜。
  • 學(xué)習(xí)小程序俺榆,自定義導(dǎo)航欄是很重要的技能感昼,其間的邏輯并不復(fù)雜,還是和學(xué)習(xí)前端一樣罐脊,需要非常細(xì)心耐心定嗓,才能做好細(xì)節(jié)工作。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末萍桌,一起剝皮案震驚了整個濱河市宵溅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌上炎,老刑警劉巖恃逻,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異藕施,居然都是意外死亡寇损,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門裳食,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矛市,“玉大人,你說我怎么就攤上這事诲祸∽抢簦” “怎么了而昨?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長找田。 經(jīng)常有香客問我歌憨,道長,這世上最難降的妖魔是什么墩衙? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任躺孝,我火速辦了婚禮,結(jié)果婚禮上底桂,老公的妹妹穿的比我還像新娘植袍。我一直安慰自己,他們只是感情好籽懦,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布于个。 她就那樣靜靜地躺著,像睡著了一般暮顺。 火紅的嫁衣襯著肌膚如雪厅篓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天捶码,我揣著相機(jī)與錄音羽氮,去河邊找鬼。 笑死惫恼,一個胖子當(dāng)著我的面吹牛档押,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播祈纯,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼令宿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了腕窥?” 一聲冷哼從身側(cè)響起粒没,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎簇爆,沒想到半個月后癞松,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡入蛆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年响蓉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片安寺。...
    茶點(diǎn)故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡厕妖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出挑庶,到底是詐尸還是另有隱情言秸,我是刑警寧澤软能,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站举畸,受9級特大地震影響查排,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜抄沮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一跋核、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧叛买,春花似錦砂代、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至椒功,卻和暖如春捶箱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背动漾。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工丁屎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人旱眯。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓晨川,卻偏偏與公主長得像,于是被迫代替她去往敵國和親键思。 傳聞我的和親對象是個殘疾皇子础爬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容