如今,市面上的屏幕尺寸和全面屏方案五花八門。這裏我使用了小米的圖來講明:
上述兩種屏幕均可以統稱爲劉海屏,不過對於右側較小的劉海,業界通常稱爲水滴屏或美人尖。爲便於說明,後文提到的「劉海屏」「劉海區」都同時指代上圖兩種屏幕。html
當咱們在談屏幕適配時,咱們具體談什麼呢?android
其中第一點是全部應用都須要適配的,對應下文的聲明最大長寬比,而第二點,若是應用自己不須要全屏顯示或使用沉浸式狀態欄,是不須要適配的。c#
針對須要適配第二點的應用,須要獲取劉海的位置和寬高,而後將顯示內容避開便可。api
之前的普通屏長寬比爲16:9,全面屏手機的屏幕長寬比增大了不少,若是不適配的話就會相似下面這樣:app
適配方式有兩種:ide
這個操做將會爲<application>
標籤隱式添加一個屬性,android:resizeableActivity="true", 該屬性的做用後面將詳細說明。函數
<!-- Render on full screen up to screen aspect ratio of 2.4 --> <!-- Use a letterbox on screens larger than 2.4 --> <meta-data android:name="android.max_aspect" android:value="2.4" />
在 Android 7.0(API 級別 24)或更高版本的應用,android:resizeableActivity屬性默認爲true(對應適配方式1)。這個屬性是控制多窗口顯示的,決定當前的應用或者Activity是否支持多窗口。佈局
能夠在清單的<activity>
或 <application>
節點中設置該屬性,啓用或禁用多窗口顯示,配置以下:ui
android:resizeableActivity=["true" | "false"]
若是該屬性設置爲 true,Activity 將能以分屏和自由形狀模式啓動。 若是此屬性設置爲 false,Activity 將不支持多窗口模式。 若是該值爲 false,且用戶嘗試在多窗口模式下啓動 Activity,該 Activity 將全屏顯示。google
適配方式2即爲設置屏幕的最大長寬比,這是官方提供的設置方式。
若是設置了最大長寬比,必須android:resizeableActivity="false"。 不然最大長寬比沒有任何做用。
Android P(9.0)開始,官方開始提供了官方的挖孔屏適配API,具體能夠參考Support display cutouts。
經過Android P提供的 DisplayCutout 類,能夠肯定非功能區域的位置和形狀,這些區域不該顯示內容。 要肯定這些凹口屏幕區域是否存在及其位置,請使用 getDisplayCutout() 函數。
全新的窗口布局屬性 layoutInDisplayCutoutMode 讓您的應用能夠爲設備凹口屏幕周圍的內容進行佈局。 您能夠將此屬性設爲下列值之一:
默認值是LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT,劉海區域不會顯示內容,須要顯示時能夠將值設置爲LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES。
您能夠按以下步驟在任何運行 Android P 的設備或模擬器上模擬屏幕缺口:
適配參考示例:
// 延伸顯示區域到劉海 WindowManager.LayoutParams lp = window.getAttributes(); lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; window.setAttributes(lp); // 設置頁面全屏顯示 final View decorView = window.getDecorView(); decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
其中延伸顯示區域到劉海的代碼,也能夠經過修改Activity或應用的style實現,例如:
<?xml version="1.0" encoding="utf-8"?> <resources> <style name="AppTheme" parent="xxx"> <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> </style> </resources>
因Google官方的適配方案到Android P才推出,所以在Android O(8.0版本)設備上,各家廠商有本身的實現方案。
方案一:
<meta-data android:name="android.notch_support" android:value="true"/>
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:testOnly="false" android:supportsRtl="true" android:theme="@style/AppTheme"> <meta-data android:name="android.notch_support" android:value="true"/> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity>
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:testOnly="false" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".LandscapeFullScreenActivity" android:screenOrientation="sensor"> </activity> <activity android:name=".FullScreenActivity"> <meta-data android:name="android.notch_support" android:value="true"/> </activity> </application>
方案二:
對Application生效,意味着該應用的全部頁面,系統都不會作豎屏場景的特殊下移或者是橫屏場景的右移特殊處理。
1,設置應用窗口在華爲劉海屏手機使用劉海區。
/*劉海屏全屏顯示FLAG*/ public static final int FLAG_NOTCH_SUPPORT=0x00010000; /** * 設置應用窗口在華爲劉海屏手機使用劉海區 * @param window 應用頁面window對象 */ public static void setFullScreenWindowLayoutInDisplayCutout(Window window) { if (window == null) { return; } WindowManager.LayoutParams layoutParams = window.getAttributes(); try { Class layoutParamsExCls = Class.forName("com.huawei.android.view.LayoutParamsEx"); Constructor con=layoutParamsExCls.getConstructor(LayoutParams.class); Object layoutParamsExObj=con.newInstance(layoutParams); Method method=layoutParamsExCls.getMethod("addHwFlags", int.class); method.invoke(layoutParamsExObj, FLAG_NOTCH_SUPPORT); } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |InstantiationException | InvocationTargetException e) { Log.e("test", "hw add notch screen flag api error"); } catch (Exception e) { Log.e("test", "other Exception"); } }
2.清除添加的華爲劉海屏Flag,恢復應用不使用劉海區顯示。
public static void setNotFullScreenWindowLayoutInDisplayCutout (Window window) { if (window == null) { return; } WindowManager.LayoutParams layoutParams = window.getAttributes(); try { Class layoutParamsExCls = Class.forName("com.huawei.android.view.LayoutParamsEx"); Constructor con=layoutParamsExCls.getConstructor(LayoutParams.class); Object layoutParamsExObj=con.newInstance(layoutParams); Method method=layoutParamsExCls.getMethod("clearHwFlags", int.class); method.invoke(layoutParamsExObj, FLAG_NOTCH_SUPPORT); } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |InstantiationException | InvocationTargetException e) { Log.e("test", "hw clear notch screen flag api error"); } catch (Exception e) { Log.e("test", "other Exception"); } }
private static boolean isNotch() { try { Method getInt = Class.forName("android.os.SystemProperties").getMethod("getInt", String.class, int.class); int notch = (int) getInt.invoke(null, "ro.miui.notch", 0); return notch == 1; } catch (Throwable ignore) { } return false; }
@Override public void setDisplayInNotch(Activity activity) { int flag = 0x00000100 | 0x00000200 | 0x00000400; try { Method method = Window.class.getMethod("addExtraFlags", int.class); method.invoke(activity.getWindow(), flag); } catch (Exception ignore) { } }
public static int getNotchHeight(Context context) { int resourceId = context.getResources().getIdentifier("notch_height", "dimen", "android"); if (resourceId > 0) { return context.getResources().getDimensionPixelSize(resourceId); } return 0; } public static int getNotchWidth(Context context) { int resourceId = context.getResources().getIdentifier("notch_width", "dimen", "android"); if (resourceId > 0) { return context.getResources().getDimensionPixelSize(resourceId); } return 0; }
@Override public boolean hasNotch(Activity activity) { boolean ret = false; try { ret = activity.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism"); } catch (Throwable ignore) { } return ret; }
private static String getScreenValue() { String value = ""; Class<?> cls; try { cls = Class.forName("android.os.SystemProperties"); Method get = cls.getMethod("get", String.class); Object object = cls.newInstance(); value = (String) get.invoke(object, "ro.oppo.screen.heteromorphism"); } catch (Throwable ignore) { } return value; }
參考連接:
聲明受限屏幕支持:聲明最大長寬比
Android 8.1 兼容性定義
多窗口支持
Support display cutouts
華爲劉海屏手機安卓O版本適配指導
OPPO凹形屏適配說明
vivo 全面屏應用適配指南
小米劉海屏水滴屏 Android O 適配
附件:https://download.csdn.net/dow...