應該會有人覺得百度()有的東西為什么我會寫出來?有我還寫啥啊~
手上有一個項目,是用+vue的,這個不是重點,由于ios的app上架比較困難,所以優先上架。
因為習慣了在ios上透明狀態欄的樣式,在上也想擁有。得賴于ios的css中safe-area-inset-*的屬性,可以在的ios端結合--插件實現透明狀態欄,并且在頂部(或者底部android44 狀態欄顏色,根據需要),讓出安全距離,避免被頂部狀態欄文字和底部橫線擋住,于是心想在安卓也可以吧~
可以我就不寫這篇了!!!!
預期效果如圖
首先,貿然使用safe-area-inset-*在安卓上會出現2大問題!
1、沒效果!
--插件已經可以使得狀態欄變得透明,且根據需要變換字體顏色?然而本該出現安全距離卻沒有也就是默認0?
值得注意的是,在我大量測試后發現,單獨通過一句透明化狀態欄的代碼去實現是不可以的,我不知道是不是我的用法不對,還是確實是這樣。這里我用了3句代碼才實現了透明化。放代碼!!
StatusBar.show(); StatusBar.overlaysWebView(false); StatusBar.overlaysWebView(true);
經過查看相關文檔發現,該屬性是ios獨有的。
2、不兼容部分內核導致樣式出錯
沒效果是最好的情況,我在同事的uc瀏覽器,無論手機版還是pc版都出現了由于不兼容safe-area-inset-*屬性導致整個樣式無法被渲染,出現了驗證的樣式bugandroid44 狀態欄顏色,其實本該默認這個值為0的,卻在部分內核下無法被識別。
推測,應該是使用了較低版本的內核導致的問題,所以出現了這個問題。
綜上:解決問題迫在眉睫;
我們先解決第二個問題;
因為在本項目css中使用大量的calc方法,大膽推測var方法定義是沒問題的。小范圍實現證實想法!
:root是根結點也就是html,我們需要在里面重新定義safe-area-inset-*值!
值得一提的是,ios11于ios12使用safe-area-inset-*的方法是不一樣的
ios11及以下使用(safe-area-inset-*)
ios12使用env(safe-area-inset-*)
在考慮用戶群體可能使用ios11的情況下,必須統一,于是css兼容代碼就誕生了
:root?{ ??--safe-area-inset-top:?0px; ??--safe-area-inset-right:?0px; ??--safe-area-inset-bottom:?0px; ??--safe-area-inset-left:?0px; ??@supports?(top:?constant(safe-area-inset-top))?{ ????--safe-area-inset-top:?constant(safe-area-inset-top); ????--safe-area-inset-right:?constant(safe-area-inset-right); ????--safe-area-inset-bottom:?constant(safe-area-inset-bottom); ????--safe-area-inset-left:?constant(safe-area-inset-left); ??} ??@supports?(top:?env(safe-area-inset-top))?{ ????--safe-area-inset-top:?env(safe-area-inset-top); ????--safe-area-inset-right:?env(safe-area-inset-right); ????--safe-area-inset-bottom:?env(safe-area-inset-bottom); ????--safe-area-inset-left:?env(safe-area-inset-left); ??} }
通過探針我們對把支持safe-area-inset-*賦予--safe-area-inset-*,對不支持的,一律賦值0px!!!
謹記,這里不能寫0,必須是完整的0px;否則可能無效
最后,在凡是用到safe-area-inset-*的地方,改寫為var(--safe-area-inset-*)
例如
div{ ????top:calc(44px?-?var(--safe-area-inset-top)); }
解決第二個問題了
回頭我們攻克第一個問題
其實第二個問題網上有,只是沒這么詳細,第一個問題,也不必強求解決,但是對于喜歡研究的程序員來說,是一個研究的機會。
要解決第一個問題,必須基于第二個問題的基礎上。
我們用的--插件是不支持獲取狀態欄高度的,這就是為什么需要用css讓出安全距離的一個原因。
假如,我們可以通過js獲取到狀態欄高度,利用第二個問題的css,動態拼接初始值動態寫入html中,由于vue是單頁應用,所以只要要寫入一次,對所有的頁面都必定是有效的。
要想獲得狀態欄高度,必須改寫安卓代碼,方法有2個
1、我用的是騰訊的X5內核,去改寫其代碼,在獲取狀態欄高度后,通過css注入到中!!研究了一個早上太過于硬核,放棄!
2、修改--,使得我們可以用js去獲取狀態欄高度
放出代碼,語法就不說了,需要會寫安卓的人,我也是各自嘗試再寫出來的!
找到這個java文件,并寫入代碼
if?("getStatusBarHeight".equals(action))?{ ????????????int?result?=?0; ????????????try?{ ????????????????DisplayMetrics?dm?=?new?DisplayMetrics(); ????????????????dm?=?cordova.getActivity().getResources().getDisplayMetrics(); ????????????????float?density?=?dm.density; ????????????????int?resourceId?=?cordova.getActivity().getResources().getIdentifier("status_bar_height",?"dimen",?"android"); ????????????????if?(resourceId?>?0)?{ ????????????????????result?=?cordova.getActivity().getResources().getDimensionPixelSize(resourceId); ????????????????} ????????????????Log.i("getStatusBarHeight",?String.valueOf(result?/?density)); ????????????????callbackContext.success(String.valueOf((result?/?density))); ????????????}?catch?(Exception?e)?{ ????????????????callbackContext.error("error"); ????????????} ????????}
調試輸出的語句大可去掉就好。找到對應的js文件
加入
getStatusBarHeight:function(success,?error){ ??exec(success,?error,'StatusBar','getStatusBarHeight',[]) },
在vue入口文件main.ts(或者main.js)中的監聽中加入ts(js)代碼
StatusBar.getStatusBarHeight((height:?string)?=>?{ ????????????if?(Number(height)?>?0)?{ ????????????????//一些錯誤規避 ????????????????//StatusBar.show(); ????????????????//StatusBar.overlaysWebView(false); ????????????????//StatusBar.overlaysWebView(true); ????????????????const?code:?string?=?`:root{--safe-area-inset-top:${height}px;--safe-area-inset-right:0px;--safe-area-inset-bottom:0px;--safe-area-inset-left:0px;`?+ ????????????????????`@supports(top:constant(safe-area-inset-top)){--safe-area-inset-top:constant(safe-area-inset-top);--safe-area-inset-right:constant(safe-area-inset-right);`?+ ????????????????????`--safe-area-inset-bottom:constant(safe-area-inset-bottom);--safe-area-inset-left:constant(safe-area-inset-left)}`?+ ????????????????????`@supports(top:env(safe-area-inset-top)){--safe-area-inset-top:env(safe-area-inset-top);--safe-area-inset-right:env(safe-area-inset-right);`?+ ????????????????????`--safe-area-inset-bottom:env(safe-area-inset-bottom);--safe-area-inset-left:env(safe-area-inset-left)}}`; ????????????????const?style:?any?=?document.createElement('style'); ????????????????style.type?=?'text/css'; ????????????????style.rel?=?'stylesheet'; ????????????????style.appendChild(document.createTextNode(code)); ????????????????const?head:?any?=?document.getElementsByTagName('head')[0]; ????????????????head.appendChild(style); ????????????????StatusBar.styleDefault(); ????????????}?else?{ ????????????????StatusBar.show(); ????????????}
然后編譯,測試,微調,完美解決!!