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

一、發現問題

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

  • 機型多如牛毛:自定義導航欄高度在不一樣機型始終沒法達到視覺上的統一;
  • 調皮的膠囊按鈕:導航欄元素(文字,圖標等)怎麼也對不齊那該死的膠囊按鈕;
  • 各類尺寸的全面屏,奇怪的劉海屏,簡直要抓狂。

一樣的,這些問題也是小灰經歷過的。可是小灰相信,辦法總比問題多,因而開始了本身的探究:git

二、一探究竟

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

169d422007d60196?w=2482&h=492&f=png&s=307793

從圖中分析,咱們能夠獲得以下信息:小程序

  • Android跟iOS有差別,表如今頂部到膠囊按鈕之間的距離差了6pt
  • 膠囊按鈕高度爲32pt, iOS和Android一致

這。。。,好像並無什麼L用啊??這僅僅是普通屏幕爲參照的,ipx, 安卓全面屏徹底沒介紹。
沉着冷靜,咱們接着分析:微信

  • 膠囊按鈕到狀態欄下邊緣這塊距離,好像是固定的?
  • 安卓這個圖,好像有點奇怪?導航欄分爲 狀態欄+標題欄?
  • 若是車兩個條件成立,那咱們的問題是否是就解決了80%了?

那麼咱們來論證一下:app

第一個問題:膠囊按鈕到狀態欄下邊緣的距離是否是固定的?xss

很簡單,咱們寫一個狀態欄,經過wx.getSystemInfoSync().statusBarHeight設置高度
爲了好測量,咱們設置狀態欄背景色爲深色
js代碼:flex

var sysinfo = wx.getSystemInfoSync();
this.setData({ 
     statusBarHeight:sysinfo.statusBarHeight 
})

wxml代碼:ui

<view class="status-bar" style="height:{{statusBarHeight}}px"></view>

wxss代碼:this

.status-bar{
    background: rgb(141, 71, 71);
 }

效果圖(iPhone6):

169d46522c51dde4?w=756&h=188&f=png&s=16261

效果圖(iPhoneX):

169d4668092ad319?w=748&h=206&f=png&s=15022

效果圖(安卓):
169d475f38427b32?w=718&h=186&f=png&s=15776

是否是有點眉目了?是的,從截圖能夠看出,iOS是一致的,可是Android好像有所差異。
那究竟距離是多少?咱們用神器(微信截圖)來量一量:

Android:
169d47c7bc7e6798?w=762&h=666&f=png&s=64794

iOS:
169d47f76e2cbcc8?w=812&h=666&f=png&s=67052

能夠看出,iOS膠囊按鈕與狀態欄之間距離爲:6px, Android爲8px,而且通過測量,iOS各機型,Android各機型結果一致(因爲篇幅緣由,就不一一展現截圖了,有興趣的能夠自行測量)

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

經過對第一個問題的論證,很明顯能看出來確實是這樣的。而且經過第一個問題的測量結果以及官方提供的數據,咱們能夠對標題欄高度進行計算:
  • 導航欄高度 = 膠囊按鈕高度 + 狀態欄到膠囊按鈕間距 * 2
  • Android導航欄高度 = 32px + 8px * 2 = 48px
  • iOS導航欄高度 = 32px + 6px * 2 = 44px

*注:因爲膠囊按鈕是原生組件,爲表現一直,其單位在個系統都爲px,因此咱們的自定義導航欄各個高度的單位都必需是px(切記不能用rpx),才能完美適配。

三、解決問題

經過上述分析,相信小夥伴們都能有一個解決問題的思路了,在上代碼以前,小灰再給你們畫一下重點:

  • 寫自定義導航組件的時候,須要將組件結構一分爲二:狀態欄 + 標題欄
  • 狀態欄高度可經過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>        [連接描述][10]
    <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;
}

運行效果圖:
169d49ab1b497a06?w=748&h=181&f=png&s=19336
文字標題:

169d49deca93da69?w=746&h=132&f=png&s=19980

圖片標題:
169d49c23c3c9a66?w=750&h=174&f=png&s=19465

四、總結

通過小灰的一番論證以及實踐經驗,最終總結出以上最終解決方案,但但願對小夥伴們有所幫助,若是小夥伴們以爲有用,記得給顆star哦 --> 點我,後續還會更新其餘組件。

若是你們有更好的方案或者以爲小灰的方案有問題,歡迎你們留言。

相關文章
相關標籤/搜索