小程式自定義導航欄適配(完美版)

小灰??發表於2019-03-31

1、發現問題

    小程式頁面自定義導航欄功能已經開放有些日子了(還不知道這個功能的可以先>>瞭解一下),這極大的提升了小程式開發的自由度,相信不少小夥伴已經使用過這個功能,同時也相信不少小夥伴在此功能開發過程中踩過同樣的一些坑:

  1. 機型多如牛毛:自定義導航欄高度在不同機型始終無法達到視覺上的統一;
  2. 調皮的膠囊按鈕:導航欄元素(文字,圖示等)怎麼也對不齊那該死的膠囊按鈕;
  3. 各種尺寸的全面屏,奇怪的劉海屏,簡直要抓狂。
同樣的,這些問題也是小灰經歷過的。但是小灰相信,辦法總比問題多,於是開始了自己的探究:

2、一探究竟

    為了搞明白到底該怎麼去適配,老規矩,我先翻了一波官方文件,還別說,官方還真有這麼一段介紹了相關細節,>>詳情點選

小程式自定義導航欄適配(完美版)

從圖中分析,我們可以得到如下資訊:

  1. Android跟iOS有差異,表現在頂部到膠囊按鈕之間的距離差了6pt
  2. 膠囊按鈕高度為32pt, iOS和Android一致

這。。。,好像並沒有什麼L用啊??這僅僅是普通螢幕為參照的,ipx, 安卓全面屏完全沒介紹。

沉著冷靜,我們接著分析:

  1. 膠囊按鈕到狀態列下邊緣這塊距離,好像是固定的?
  2. 安卓這個圖,好像有點奇怪?導航欄分為 狀態列+標題欄?
如果車兩個條件成立,那我們的問題是不是就解決了80%了?

那麼我們來論證一下:

第一個問題:膠囊按鈕到狀態列下邊緣的距離是不是固定的

  • 很簡單,我們寫一個狀態列,通過wx.getSystemInfoSync().statusBarHeight設定高度
  • 為了好測量,我們設定狀態列背景色為深色
js程式碼:

    var sysinfo = wx.getSystemInfoSync();
    this.setData({ 
         statusBarHeight:sysinfo.statusBarHeight 
    })複製程式碼

wxml程式碼:

<view class="status-bar" style="height:{{statusBarHeight}}px"></view>複製程式碼

wxss程式碼:

.status-bar{    background: rgb(141, 71, 71);}複製程式碼

效果圖(iPhone6):

小程式自定義導航欄適配(完美版)

效果圖(iPhoneX):

小程式自定義導航欄適配(完美版)

效果圖(安卓):

小程式自定義導航欄適配(完美版)

是不是有點眉目了?是的,從截圖可以看出,iOS是一致的,但是Android好像有所差別。

那究竟距離是多少?我們用神器(微信截圖)來量一量:

Android:

小程式自定義導航欄適配(完美版)

iOS:

小程式自定義導航欄適配(完美版)

可以看出,iOS膠囊按鈕與狀態列之間距離為:6px, Android為8px,並且經過測量,iOS各機型,Android各機型結果一致(由於篇幅原因,就不一一展示截圖了,有興趣的可以自行測量)

第二個問題:導航欄分為 狀態列+標題欄?

    通過對第一個問題的論證,很明顯能看出來確實是這樣的。並且通過第一個問題的測量結果以及官方提供的資料,我們可以對標題欄高度進行計算:

導航欄高度 = 膠囊按鈕高度 + 狀態列到膠囊按鈕間距 * 2                                                                Android導航欄高度 = 32px + 8px * 2 = 48px                                                                                        iOS導航欄高度 = 32px + 6px * 2 = 44px

*注:由於膠囊按鈕是原生元件,為表現一致,其單位在個系統都為px,所以我們的自定義導航欄各個高度的單位都必需是px(切記不能用rpx),才能完美適配。


3、解決問題

通過上述分析,相信小夥伴們都能有一個解決問題的思路了,在上程式碼之前,小灰再給大家畫一下重點:

  • 寫自定義導航元件的時候,需要將元件結構一分為二:狀態列 + 標題欄
  • 狀態列高度可通過wx.getSystemInfoSync().statusBarHeight獲取
  • 標題欄高度:安卓:48px,iOS:44px
  • 單位必需跟膠囊按鈕一致,用px
話不多說,上程式碼(gitHub地址):

js:

Component({   
   properties: {        
    background: {            
        type: String,            
        value: 'rgba(255, 255, 255, 1)'        
    },        
    color: {            
        type: String,            
        value: 'rgba(0, 0, 0, 1)'        
    },        
    titleText: {            
        type: String,            
        value: '導航欄'        
    },        
    titleImg: {            
        type: String,            
        value: ''        
    },        
    backIcon: {            
        type: String,            
        value: ''        
     },        
    homeIcon: {            
        type: String,            
        value: ''        
    },        
    fontSize: {            
        type: Number,            
        value: 16        
    },        
    iconHeight: {            
        type: Number,            
        value: 19       
    },        
    iconWidth: {            
        type:Number,            
        value: 58        
    }    
   },    
attached: function(){        
    var that = this;        
    that.setNavSize();        
    that.setStyle();    
   },    
 data: {
    },    
methods: {        
// 通過獲取系統資訊計算導航欄高度        
setNavSize: function() {            
var that = this                
    , sysinfo = wx.getSystemInfoSync()                
    , statusHeight = sysinfo.statusBarHeight                
    , isiOS = sysinfo.system.indexOf('iOS') > -1                
    , navHeight;            
if (!isiOS) {                
    navHeight = 48;            
   } else {                
    navHeight = 44;            
}            
that.setData({                
    status: statusHeight,                
    navHeight: navHeight            
  })        
},        
setStyle: function() {            
    var that  = this                
    , containerStyle                
    , textStyle                
    , iconStyle;            
    containerStyle = [                
        'background:' + that.data.background                
        ].join(';');            
        textStyle = [                
        'color:' + that.data.color,                
        'font-size:' + that.data.fontSize + 'px'            
        ].join(';');            
        iconStyle = [                
        'width: ' + that.data.iconWidth + 'px',                
        'height: ' + that.data.iconHeight + 'px'            
        ].join(';');            
        that.setData({               
             containerStyle: containerStyle,                
             textStyle: textStyle,                
             iconStyle: iconStyle            
        })        },        
        // 返回事件        
back: function(){            
    wx.navigateBack({                
        delta: 1            
    })            
    this.triggerEvent('back', {back: 1})        
},        
home: function() {            
    this.triggerEvent('home', {});       
 }   
 }})



複製程式碼

wxml:

<view class='nav' style='height: {{status + navHeight}}px'>    
<view class='status' style='height: {{status}}px;{{containerStyle}}'></view>    <view class='navbar' style='height:{{navHeight}}px;{{containerStyle}}'>        <view class='back-icon' wx:if="{{backIcon}}" bindtap='back'>                    <image src='{{backIcon}}'></image>       
     </view>        
<view class='home-icon' wx:if="{{homeIcon}}" bindtap='home'>            
    <image src='{{homeIcon}}'></image>        
</view>        
<view class='nav-icon' wx:if="{{titleImg}}">            
<image src='{{titleImg}}' style='{{iconStyle}}'></image>       
 </view>
        <view class='nav-title' wx:if="{{titleText && !titleImg}}">
            <text style='{{textStyle}}'>{{titleText}}</text>
        </view>
    </view>
</view>複製程式碼

wxss:

.navbar{    position: relative}.back-icon, .home-icon{    width: 28px;    height: 100%;    position: absolute;    transform: translateY(-50%);    top: 50%;    display: flex;}.back-icon{    left: 16px;}.home-icon{    left: 44px}.back-icon image{    width: 28px;    height: 28px;    margin: auto;}.home-icon image{    width: 20px;    height: 20px;    margin: auto;}.nav-title, .nav-icon{    position: absolute;    transform: translate(-50%, -50%);    left: 50%;    top: 50%;    font-size: 0;    font-weight: bold;}複製程式碼

執行效果圖:

文字標題:

小程式自定義導航欄適配(完美版)

小程式自定義導航欄適配(完美版)

圖片標題:

小程式自定義導航欄適配(完美版)

小程式自定義導航欄適配(完美版)

4、總結

經過小灰的一番論證以及實踐經驗,最終總結出以上最終解決方案,但希望對小夥伴們有所幫助,如果小夥伴們覺得有用,記得給顆star哦 --> 點我,後續還會更新其他元件。

如果大家有更好的方案或者覺得小灰的方案有問題,歡迎大家留言。


相關文章