Android劉海屏、水滴屏全面屏適配

如今,市面上的屏幕尺寸和全面屏方案五花八門。這裏我使用了小米的圖來講明:
在這裏插入圖片描述
上述兩種屏幕均可以統稱爲劉海屏,不過對於右側較小的劉海,業界通常稱爲水滴屏或美人尖。爲便於說明,後文提到的「劉海屏」「劉海區」都同時指代上圖兩種屏幕。html

劉海屏、水滴屏全面屏適配細節

當咱們在談屏幕適配時,咱們具體談什麼呢?android

  • 適應更長的屏幕
  • 防止內容被劉海遮擋

其中第一點是全部應用都須要適配的,對應下文的聲明最大長寬比,而第二點,若是應用自己不須要全屏顯示或使用沉浸式狀態欄,是不須要適配的。c#

針對須要適配第二點的應用,須要獲取劉海的位置和寬高,而後將顯示內容避開便可。api

聲明最大長寬比

之前的普通屏長寬比爲16:9,全面屏手機的屏幕長寬比增大了不少,若是不適配的話就會相似下面這樣:
在這裏插入圖片描述app

適配方式

適配方式有兩種:ide

  1. 將targetSdkVersion版本設置到API 24及以上;

這個操做將會爲<application> 標籤隱式添加一個屬性,android:resizeableActivity="true", 該屬性的做用後面將詳細說明。函數

  1. 在 <application> 標籤中增長屬性:android:resizeableActivity="false",同時在節點下增長一個meta-data標籤:
<!-- 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"。 不然最大長寬比沒有任何做用。

適配劉海屏

Android9.0適配

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
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER

默認值是LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT,劉海區域不會顯示內容,須要顯示時能夠將值設置爲LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES。

您能夠按以下步驟在任何運行 Android P 的設備或模擬器上模擬屏幕缺口:

  1. 啓用開發者選項;
  2. 在 Developer options 屏幕中,向下滾動至 Drawing 部分並選擇 Simulate a display with a cutout。

適配參考示例:

// 延伸顯示區域到劉海
 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>

Android O 適配

因Google官方的適配方案到Android P才推出,所以在Android O(8.0版本)設備上,各家廠商有本身的實現方案。

華爲Android O適配

方案一:

  1. 具體方式以下所示:
<meta-data android:name="android.notch_support" android:value="true"/>
  1. 對Application生效,意味着該應用的全部頁面,系統都不會作豎屏場景的特殊下移或者是橫屏場景的右移特殊處理。例如:
<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>
  1. 對Activity生效,意味着能夠針對單個頁面進行劉海屏適配,設置了該屬性的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");
     }
 }

小米Android O適配

  1. 判斷是不是劉海屏。
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;
 }
  1. 設置顯示到劉海區域
@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) {
     }
 }
  1. 獲取劉海寬高
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;
 }

oppo Android O適配

  1. 判斷是不是劉海屏
@Override
 public boolean hasNotch(Activity activity) {
     boolean ret = false;
     try {
         ret = activity.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
     } catch (Throwable ignore) {
     }
     return ret;
 }
  1. 獲取劉海的左上角和右下角的座標
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...

相關文章
相關標籤/搜索