Hi,你們好,我是承香墨影!程序員
Apple 一直在引領設計的潮流,自從 iPhone X 發佈以後,"劉海屏" 就一直存在爭議。不過無論你怎樣,Android 也要躋入 "劉海屏" 的行列,尤爲是 Android P 發佈以後,也從系統級支持頂部凹槽屏幕設計。c#
不少廠商也在逐漸推出 「劉海屏」 設計的手機,在國內比較常見的就是 OPPO R15 和 華爲 P20。安全
屏幕不同了,迎來的就是一些適配上的問題。今天就來聊聊,Android 的 「劉海屏」,以及咱們如何去適配它。bash
劉海屏的外觀,我想你們應該都有概念,不過不一樣廠商劉海屏的實現方式也有所不太,這一點須要先有個概念。ide
就如今市場上的狀況來講,會區分紅兩類,一類是標準的 Android P Api,另一類就是廠商在 Android P 如下的系統,作的特殊適配。佈局
例如:華爲 P20 就是採用的 Android P 標準 Api 的方式,而 OPPO R15 就不同了,它有本身的適配 Api。post
就算是增長了劉海屏,你也能夠發現,大部分都是「切割」的狀態欄的區域,因此就面臨了三種狀況。學習
後面會單獨講解這幾種方式的區別。區塊鏈
在手邊沒有對應系統的設備的時候,模擬器是一條不錯的路,最近 Google 也發佈了 Android P 的模擬器,還有一個辦法就是找一些支持真機雲測的平臺,租用一臺須要的遠程設備,也是一個解決方案。spa
我這裏選擇 Android P 的模擬器,有須要本身更新 SDK ,無腦下載更新就好。
劉海的凹槽區域,大部分是爲了給攝像頭或者其餘傳感器留出區域。而在沒有劉海的設備或者模擬器上,能夠經過開發者選項裏的 「Simulate a display with a cutout」,開啓劉海屏的支持。
若是你把全部的模式都試過一遍,你會發現,其實劉海屏的劉海,在 Android P 上,是有多種樣式的,並不是統一的。
2.2 也講清楚了,劉海屏的切割區域,都存在於狀態欄上,因此在有狀態欄的頁面上,是無需咱們特殊處理的,系統會幫咱們處理好。
而對於全屏的頁面,就須要單獨的處理了。我這裏,簡單作了一個全屏頁面,每一個橫條都是等寬的這樣能看到佈局上的差別。
從左至右分別是:關閉劉海屏、開啓劉海屏但不支持、適配劉海屏。
一個全屏的頁面,當沒有支持劉海屏又碰到了劉海屏,會致使 UI 下沉,若是這不是一個列表的佈局,底部的控件就會被遮擋。
例以下面這樣的狀況:
還有一些被劉海遮擋區域的效果,其實主要是依賴 UI 設計師來規避了,不要在可能出現劉海切割的地方,設計可操做的區域,影響用戶操做。
說那麼多,最終咱們仍是須要用技術的方式來適配劉海屏。Android P 的劉海屏,是有標準的 Api 來進行適配,而對於一些廠商本身的劉海屏設備,例如:OPPO R15,就須要遵循它的開發文檔進行單獨適配。
Android P 爲最新的劉海屏,提供了專門的 Api 來支持:DisplayCutout。
咱們在全屏的頁面,須要單獨開啓支持劉海屏。而 Google 提供的適配方案,能夠設置是否在全屏模式下,使用劉海屏的區域。
WindowManager.LayoutParams lp
=getWindow().getAttributes();
lp.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
getWindow().setAttributes(lp);
複製代碼
新的佈局屬性 layoutInDisplayCutoutMode
包含三種可選的模式,
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1;
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0;
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2;
複製代碼
在全屏模式下,咱們須要有辦法獲取到劉海屏凹槽的高度,才能夠作到設計和佈局的時候,留出安全距離。
雖然 Google 要求,劉海屏的凹槽,必須和劉海的高度保持一致,而劉海屏又被隱藏在狀態欄了,因此有一個思路是直接獲取狀態欄的高度,來判斷劉海以外,可佈局的安全區域。
不過 Android P 已經預留出了標準的測量 劉海屏凹槽 的 Api:DisplayCutout
。
劉海屏的凹槽,就在屏幕的中間,因此只有 getSafeInsetTop()
方法返回的結果,是咱們須要的,而其餘的 getSafeInsetXxx()
方法,直接返回的是 0 。
view.postDelayed(new Runnable() {
@Override
public void run() {
DisplayCutout displayCutout = view.getRootWindowInsets().getDisplayCutout();
Log.i("cxmyDev", "SafeInsetBottom:" + displayCutout.getSafeInsetBottom());
Log.i("cxmyDev", "SafeInsetLeft:" + displayCutout.getSafeInsetLeft());
Log.i("cxmyDev", "SafeInsetRight:" + displayCutout.getSafeInsetRight());
Log.i("cxmyDev", "SafeInsetTop:" + displayCutout.getSafeInsetTop());
}
}, 100);
複製代碼
獲得的結果,也能夠看一下:
I/cxmyDev: SafeInsetBottom:0
I/cxmyDev: SafeInsetLeft:0
I/cxmyDev: SafeInsetRight:0
I/cxmyDev: SafeInsetTop:112
複製代碼
像 OPPO 這樣的廠商,實現劉海屏的方式,也並非按照 Android P 的標準作的,它徹底是本身修改了劉海屏的實現方式。不過好在,都是會提供完備的適配文檔,這就須要咱們直接閱讀他們提供的開發文檔來進行適配。
oppo 的劉海屏適配文檔:
https://open.oppomobile.com/wiki/doc#id=10139
對於 OPPO 而言,它劉海的高度是固定的,就是 80px。
判斷當前設備是不是劉海屏,也提供了對應的 Api,能夠用如下方法獲取。
context.getPackageManager().hasSystemFeature(「com.oppo.feature.screen.heteromorphism」)
複製代碼
返回 true 爲劉海屏,可是這種方法只能識別 OPPO 品牌所支持的劉海屏。
看完本篇文章,我想你對 Android 的劉海屏也有必定的認識了。這是一個全新的適配技術,如今還不肯定不一樣廠商會不會對其微調,因此你要是碰到什麼問題,不妨在留言區留言討論。
今天在公衆號後臺回覆成長『成長』,將會獲得我整理的一些學習資料,也能回覆『加羣』,一塊兒學習進步。
推薦閱讀: