Apple一直在引領設計的潮流,自從 iPhone X 發布之后,”劉海屏” 就一直存在爭議,本以為是一個美麗的錯誤(Bug),卻早就了一時間“劉海屏”的模仿潮。目前,國內已經推出的劉海屏”手機有 OPPO R15 和 華為 P20,并且Google也在IO大會上提高了相應的適配方案。
什么是劉海屏
屏幕的正上方居中位置(下圖黑色區域)會被挖掉一個孔,屏幕被挖掉的區域無法正常顯示內容,這種類型的屏幕就是劉海屏,也有其他叫法:挖孔屏、凹凸屏等等,這里統一按劉海屏命名。
就現在市場上的情況來說,“劉海屏”主要分成兩類,一類是標準的 Android P Api,另外一類就是廠商在 Android P 以下的系統,做的特殊適配。
例如:華為 P20 就是采用的 Android P 標準 Api 的方式,而 OPPO R15 就不一樣了,它有自己的適配 Api。
如何適配劉海屏
由于Android p正式版前兩天才發布, 當前市面上的Android 劉海屏手機還不能用Android 官方提供的方案來解決,那怎么辦呢?還好幾個廠商自己給出了適配方案(文末會接受使用Android P來適配劉海屏)。
華為P20
華為早在iPhone X發布后不久就推出了“劉海屏”P20,華為劉海屏適配官方文檔:
https://devcenter-test.huawei.com/consumer/cn/devservice/doc/50114
華為給出的文檔最為詳細適配文檔,P20 pro預裝系統對未做劉海屏適配處理的app有一定處理,處理的邏輯如下圖。
右上圖可知,華為系統做偏移處理的有以下2種情況:
1.未設置meta-data值,頁面橫屏狀態
2.未設置meta-data值,頁面豎屏狀態,不顯示狀態欄
適配劉海屏主要有以下幾個步驟:
1.配置meta-data
華為新增的Meta-data屬性android.notch_support在應用的AndroidManifest.xml中增加meta-data屬性,此屬性不僅可以針對Application生效,也可以對Activity配置生效,具體方式如下所示:
<meta-data android:name="android.notch_support" android:value="true"/>1
①對Application生效,意味著該應用的所有頁面,系統都不會做豎屏場景的特殊下移或者是橫屏場景的右移特殊處理:
② 對Activity生效,意味著可以針對單個頁面進行劉海屏適配,設置了該屬性的Activity系統將不會做特殊處理:
2.檢測是否存在劉海屏
public static boolean hasNotchInScreen(Context context) {
? boolean ret = false;
? try {
? ? ? ClassLoader cl = context.getClassLoader();
? ? ? Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
? ? ? Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");
? ? ? ret = (boolean) get.invoke(HwNotchSizeUtil);
? } catch (ClassNotFoundException e) {
? ? ? Log.e("test", "hasNotchInScreen ClassNotFoundException");
? } catch (NoSuchMethodException e) {
? ? ? Log.e("test", "hasNotchInScreen NoSuchMethodException");
? } catch (Exception e) {
? ? ? Log.e("test", "hasNotchInScreen Exception");
? } finally {
? ? ? return ret;
? }
}1234567891011121314151617
3.獲取劉海屏的參數
public static int[] getNotchSize(Context context) {
? int[] ret = new int[]{0, 0};
? try {
? ? ? ClassLoader cl = context.getClassLoader();
? ? ? Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
? ? ? Method get = HwNotchSizeUtil.getMethod("getNotchSize");
? ? ? ret = (int[]) get.invoke(HwNotchSizeUtil);
? } catch (ClassNotFoundException e) {
? ? ? Log.e("test", "getNotchSize ClassNotFoundException");
? } catch (NoSuchMethodException e) {
? ? ? Log.e("test", "getNotchSize NoSuchMethodException");
? } catch (Exception e) {
? ? ? Log.e("test", "getNotchSize Exception");
? } finally {
? ? ? return ret;
? }
}1234567891011121314151617
4. UI適配
通過增加上面適配方案提到的配置(meta-data或者是Flag),應用在華為劉海屏手機上就能夠默認使用劉海區顯示了,但是為了避免出現UI被劉海區遮擋的問題,還是需要應用自己做一些額外的UI適配工作:
(1)判斷是否劉海屏,通過華為劉海屏SDK的API判斷,具體參考3.2.1章節
(2)如果是劉海屏手機需要應用自己調整布局避開劉海區,布局原則:保證重要的文字、圖片和視頻信息、可點擊的控件和圖標還有應用彈窗等等布局建議顯示在狀態欄區域以下(安全區域);不重要,遮擋不會出現問題的布局可以延伸到狀態欄區域(危險區域)顯示,按照這種布局原則修改,可以一次修改就能適配所有的劉海屏手機:
獲取系統狀態欄高度接口:
public static int getStatusBarHeight(Context context) {
? ? int result = 0;
? ? int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
? ? if (resourceId > 0) {
? ? ? ? result = context.getResources().getDimensionPixelSize(resourceId);
? ? }
? ? return result;
}12345678
關于更詳細的適配資料,可以訪問華為劉海屏適配技術文檔。
vivo & OPPO
vivo 和 OPPO官網僅僅給出了適配指導,沒有給出具體方案,簡單總結為:
如有是具有劉海屏的手機,豎屏顯示狀態欄,橫屏不要在危險區顯示重要信息或者設置點擊事件。官方的文檔地址如下:
oppo官方文檔:
https://open.oppomobile.com/service/message/detail?id=61876
vivo官方文檔:
https://dev.vivo.com.cn/doc/document/info?id=103
首先,判斷是不是劉海屏手機。
OPPO判斷方法:
public static boolean hasNotchInOppo(Context context){
? return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
}123
vivo的判斷方法:
public static final int NOTCH_IN_SCREEN_VOIO=0x00000020;//是否有凹槽
public static final int ROUNDED_IN_SCREEN_VOIO=0x00000008;//是否有圓角
public static boolean hasNotchInScreenAtVoio(Context context){
? boolean ret = false;
? try {
? ? ? ClassLoader cl = context.getClassLoader();
? ? ? Class FtFeature = cl.loadClass("com.util.FtFeature");
? ? ? Method get = FtFeature.getMethod("isFeatureSupport",int.class);
? ? ? ret = (boolean) get.invoke(FtFeature,NOTCH_IN_SCREEN_VOIO);
? } catch (ClassNotFoundException e)
? { Log.e("test", "hasNotchInScreen ClassNotFoundException"); }
? catch (NoSuchMethodException e)
? { Log.e("test", "hasNotchInScreen NoSuchMethodException"); }
? catch (Exception e)
? { Log.e("test", "hasNotchInScreen Exception"); }
? finally
? { return ret; }
}12345678910111213141516171819
然后在進行適配,官方這方面的資料很少也不是很詳細
google官方
google從Android P開始為劉海屏提供支持,目前提供了一個類和三種模式:
一個類指的是可以用DisplayCutout這個類找出劉海(cutout)的位置和形狀,調用getDisplayCutout()這個方法可以獲取劉海(cutout)的位置和區域。例如:
DisplayCutout cutout = mContext.getDisplayCutout();1
Google官方提供了三種模式,分別是:
LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT:僅僅當系統提供的bar完全包含了劉海區時才允許window擴展到劉海區,否則window不會和劉海區重疊
LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES:允許window擴展到劉海區(原文說的是短邊的劉海區, 目前有劉海的手機都在短邊,所以就不糾結了)
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER:不允許window擴展到劉海區。
例如,下面是可以設置是否允許window擴展到劉海區的代碼。
WindowManager.LayoutParams lp =getWindow().getAttributes();?
lp.layoutInDisplayCutoutMode
=WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;?
getWindow().setAttributes(lp);1234
一個有狀態欄的頁面, 我們可以這樣適配:
DisplayCutout cutout = getDisplayCutout();
if(cutout != null){
WindowManager.LayoutParams lp =getWindow().getAttributes();?
lp.layoutInDisplayCutoutMode=WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;?
getWindow().setAttributes(lp);
}123456
當然如果你身邊還沒有劉海屏手機,可以使用Android P提供的模擬器,更新SDK到Android P preview版本。
然后,可以通過開發者選項里的 “Simulate a display with a cutout”,開啟劉海屏的支持,并且劉海屏有多個版本,需要注意它們的區別。
---------------------
作者:code_xzh
來源:CSDN
原文:https://blog.csdn.net/xiangzhihong8/article/details/80317682
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!