先参考一下各厂商的刘海屏适配api
华为:https://devcenter-test.huawei.com/consumer/cn/devservice/doc/50114
小米:https://dev.mi.com/console/doc/detail?pId=1293
Oppo:https://open.oppomobile.com/service/message/detail?id=61876
Vivo:https://dev.vivo.com.cn/documentCenter/doc/103
适配步骤
1.判断手机厂商,
虽然谷歌9.0已经给出了刘海屏适配的方法,但是不同厂商在刘海屏适配方面有自己的api,所以再刘海屏适配之前要先确定厂商,然后根据厂商给的api获取刘海屏高度,做屏幕适配才最方便,有效.
/**
* 是否是魅族手机(系统)
* @return
*/
public static boolean isFlyme() {
return "Meizu".equalsIgnoreCase(Build.BRAND);
}
/**
* 是否是华为荣耀
* @return
*/
public static boolean isHuawei(){
return "huawei".equalsIgnoreCase(Build.BRAND)||"Honor".equalsIgnoreCase(Build.BRAND);
}
/**
* 是否是三星
* @return
*/
public static boolean isSamsung(){
return "samsung".equalsIgnoreCase(Build.BRAND);
}
/**
* 是否是小米
* @return
*/
public static boolean isXiaomi(){
return "xiaomi".equalsIgnoreCase(Build.BRAND);
}
/**
* 是否是oppo
* @return
*/
public static boolean isOppo(){
return "oppo".equalsIgnoreCase(Build.BRAND);
}
2.判断手机是否有刘海屏
官方的方式是
/**
* 判断是否有刘海
* @param window
* @return
*/
private boolean hasDisplayCutout(Window window) {
DisplayCutout displayCutout;
View rootView = window.getDecorView();
WindowInsets insets = rootView.getRootWindowInsets();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && insets != null){
displayCutout = insets.getDisplayCutout();
if (displayCutout != null){
if (displayCutout.getBoundingRects() != null && displayCutout.getBoundingRects().size() > 0 && displayCutout.getSafeInsetTop() > 0){
return true;
}
}
}
return false;
}
这边还要考虑各个厂商 所以分别做判断
/**
* 是否是刘海屏,仅支持小米华为oppo
*
* @param activity
* @return
*/
public static boolean isNotchPhone(Activity activity) {
if (PhoneBrandUtil.isXiaomi()) {
return "1".equals(getProperty("ro.miui.notch", "0"));
} else if (PhoneBrandUtil.isHuawei()) {
return hasNotchInScreen(activity);
} else if (PhoneBrandUtil.isOppo()) {
return hasNotInOppoScreen(activity);
} else {
return false;
}
}
/**
* 华为手机是否有刘海屏
*
* @param context
* @return
*/
private 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;
}
}
/**
* oppo手机是否是刘海屏
*
* @param context
* @return
*/
private static boolean hasNotInOppoScreen(Context context) {
try {
return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
} catch (Exception e) {
return false;
}
}
/**
* 获取系统属性
*
* @param key
* @param defaultValue
* @return
*/
private static String getProperty(String key, String defaultValue) {
String value = defaultValue;
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class, String.class);
value = (String) (get.invoke(c, key, "0"));
} catch (Exception e) {
return value;
}
return value;
}
3.设置是否让内容延伸进刘海
可以通过WindowManager.LayoutParam设置刘海屏的3个参数,设置第二个为 是activity的控件可以延伸进刘海区,
//全屏模式,内容下移,非全屏模式,内容不受影响
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0;
//允许内容延伸进刘海区
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2;
//不允许内容延伸进刘海区
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1;
4.获取刘海屏高度
通过各厂商的获取刘海的高度都有自己的api和默认高度,一般刘海的高度会小于等于状态栏的高度,所以,可以先取状态栏高度作为默认值,如果取不到刘海高度,就以状态栏高度为准.
/**
* 获取状态栏高度,如果是刘海屏则获取刘海高度,目前仅适配华为、oppo和小米刘海屏
*
* @param activity
* @return
*/
public static int getNotchHigh(Activity activity) {
int statusHigh =heightForDisplayCutout(activity);
//如果是小米手机
if (PhoneBrandUtil.isXiaomi()) {
//是刘海屏
if ("1".equals(getProperty("ro.miui.notch", "0"))) {
//https://dev.mi.com/console/doc/detail?pId=1293,取刘海高度89
return 89;
} else {
return statusHigh;
}
} else if (PhoneBrandUtil.isHuawei()) {
if (hasNotchInScreen(activity)) {
return getNotchSize(activity)[1];
} else {
return statusHigh;
}
} else if (PhoneBrandUtil.isOppo()) {
if (hasNotInOppoScreen(activity)) {
//https://open.oppomobile.com/wiki/doc#id=10159
return 80;
} else {
return statusHigh;
}
} else {
return statusHigh;
}
}
/**
* 获取状态栏高度
*
*
* @return
*/
public int heightForDisplayCutout(){
int resID = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resID > 0){
return getResources().getDimensionPixelSize(resID);
}
return 96;
}
6.控件适配
一般就是 让控件的父容器做paddingTop=刘海的高度,或者控件marginTop=刘海高度