1、發現問題
小程式頁面自定義導航欄功能已經開放有些日子了(還不知道這個功能的可以先>>瞭解一下),這極大的提升了小程式開發的自由度,相信不少小夥伴已經使用過這個功能,同時也相信不少小夥伴在此功能開發過程中踩過同樣的一些坑:
- 機型多如牛毛:自定義導航欄高度在不同機型始終無法達到視覺上的統一;
- 調皮的膠囊按鈕:導航欄元素(文字,圖示等)怎麼也對不齊那該死的膠囊按鈕;
- 各種尺寸的全面屏,奇怪的劉海屏,簡直要抓狂。
2、一探究竟
為了搞明白到底該怎麼去適配,老規矩,我先翻了一波官方文件,還別說,官方還真有這麼一段介紹了相關細節,>>詳情點選:
從圖中分析,我們可以得到如下資訊:
- Android跟iOS有差異,表現在頂部到膠囊按鈕之間的距離差了6pt
- 膠囊按鈕高度為32pt, iOS和Android一致
這。。。,好像並沒有什麼L用啊??這僅僅是普通螢幕為參照的,ipx, 安卓全面屏完全沒介紹。
沉著冷靜,我們接著分析:
- 膠囊按鈕到狀態列下邊緣這塊距離,好像是固定的?
- 安卓這個圖,好像有點奇怪?導航欄分為 狀態列+標題欄?
那麼我們來論證一下:
第一個問題:膠囊按鈕到狀態列下邊緣的距離是不是固定的
- 很簡單,我們寫一個狀態列,通過wx.getSystemInfoSync().statusBarHeight設定高度
- 為了好測量,我們設定狀態列背景色為深色
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
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哦 --> 點我,後續還會更新其他元件。
如果大家有更好的方案或者覺得小灰的方案有問題,歡迎大家留言。