Android 8.0刘海屏适配

由于刘海屏设备上市时运行的是 Android O 设备,而 Android O 没有标准接口来适配刘海屏设备,因此各大厂商针对Android O刘海屏适配方案也各有差异,具体如下:

华为刘海屏手机安卓O版本适配指导

小米刘海屏 Android O 适配

OPPO凹形屏适配说明

VIVO全面屏应用适配指南

后来 Android P 中新增了刘海屏适配的API,因此开发者需要针对 Android P 的设备重新适配,使用android标准接口来适配刘海屏设备,文档如下:

Android P 官方刘海屏适配规则及 API

Android P刘海屏适配规则(小米)


Android O 8.0刘海屏适配

  • 刘海屏幕机型在界面上的问题:

1.顶部内容会被刘海部分遮挡

2.如何处理耳朵区的显示区域

  • 系统如何适配?

1.status bar 的高度必须大于等于刘海的高度;对于应用来说,相当于一个更高的 status bar.

2.当应用显示 status bar 时(如微信首页),允许应用使用耳朵区(因为 status bar 区域本身不可交互,且会显示信号、电池等信息,因此我们假定应用不会在该区域放置重要的内容和可交互的控件)

3.当应用不显示 status bar 时(如全屏游戏),不允许应用使用耳朵区,系统默认填黑

4.横屏时,默认均不允许使用耳朵区,系统默认填黑

5.不允许应用180度倒转显示

  • APP如何适配?

1.检查设备是否为Notch设备

2.确定页面是否显示状态栏

3.尽量避免同一个APP不同页面显示和隐藏状态并存(会出现页面跳变的情况(应用的可用高度变了)

4.确定是否需要横屏显示Notch区域(若显示,需兼顾notch区域在左边/右边的情况)

5.检查是否写死了状态栏的高度值。Notch机器状态栏的值是变化的,建议改为读取系统的值

6.检查普通屏幕和刘海屏幕上的显示是否正常.


小米 Android O 刘海屏适配

  • 判断设备是否为刘海屏设备

系统增加了 property ro.miui.notch,值为1时则是 Notch 屏手机

SystemProperties.getInt("ro.miui.notch", 0) == 1;

调用示例:

public static int getInt(String key,Activity activity) {
    int result = 0;
    if (isXiaomi()){
        try {
            ClassLoader classLoader = activity.getClassLoader();
            @SuppressWarnings("rawtypes")
            Class SystemProperties = classLoader.loadClass("android.os.SystemProperties");
            //参数类型
            @SuppressWarnings("rawtypes")
            Class[] paramTypes = new Class[2];
            paramTypes[0] = String.class;
            paramTypes[1] = int.class;
            Method getInt = SystemProperties.getMethod("getInt", paramTypes);
            //参数
            Object[] params = new Object[2];
            params[0] = new String(key);
            params[1] = new Integer(0);
            result = (Integer) getInt.invoke(SystemProperties, params);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return result;
}

// 是否是小米手机
public static boolean isXiaomi() {
    return "Xiaomi".equals(Build.MANUFACTURER);
}
  • 小米Application 级别的控制接口

其中,value 的取值可以是以下4种:

"none" 横竖屏都不绘制耳朵区(默认值,系统自动将应用页面下移挖孔高度的距离,保证应用布局显示在挖空区域以下)

"portrait" 竖屏绘制到耳朵区

"landscape" 横屏绘制到耳朵区

"portrait|landscape" 横竖屏都绘制到耳朵区
  • Window 级别的控制接口

如果开发者希望对特定 Window 作处理,可以使用该接口。 在 WindowManager.LayoutParams 增加 extraFlags 成员变量,用以声明该 window 是否使用耳朵区。

其中,extraFlags 有以下变量:
0x00000100 开启配置
0x00000200 竖屏配置
0x00000400 横屏配置

组合后表示 Window 的配置,如:

0x00000100 | 0x00000200 竖屏绘制到耳朵区
0x00000100 | 0x00000400 横屏绘制到耳朵区
0x00000100 | 0x00000200 | 0x00000400 横竖屏都绘制到耳朵区

控制 extraFlags 时注意只控制这几位,不要影响其他位。可以用 Window 的 addExtraFlags 和 clearExtraFlags 来修改, 这两个方法是 MIUI 增加的方法,需要反射调用。

int flag = 0x00000100 | 0x00000200 | 0x00000400;
try {
    Method method = Window.class.getMethod("addExtraFlags",
            int.class);
    method.invoke(getWindow(), flag);
} catch (Exception e) {
    Log.i(TAG, "addExtraFlags not found.");
}

华为 Android O 刘海屏适配

  • 判断设备是否为刘海屏设备
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;
    }
}
  • 应用页面设置使用刘海区显示

使用新增的Meta-data属性android.notch_support,在应用的AndroidManifest.xml中增加meta-data属性,此属性不仅可以针对Application生效,也可以对Activity配置生效。

  • 使用给window添加新增的FLAG_NOTCH_SUPPORT
  1. 接口1描述:应用通过增加华为自定义的刘海屏flag,请求使用刘海区显示:
类文件 接口 接口说明
com.huawei.android.view.LayoutParamsEx public void addHwFlags(int hwFlags) 通过添加窗口FLAG的方式设置页面使用刘海区显示:public static final int FLAG_NOTCH_SUPPORT=0x00010000;

调用范例参考:

对Application生效,意味着该应用的所有页面,系统都不会做竖屏场景的特殊下移或者是横屏场景的右移特殊处理:

/*刘海屏全屏显示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");
    }
}
  1. 接口2描述:可以通过clearHwFlags接口清除添加的华为刘海屏Flag,恢复应用不使用刘海区显示。
类文件 接口 接口说明
com.huawei.android.view.LayoutParamsEx public void clearHwFlags (int hwFlags) 通过去除窗口FLAG的方式设置页面不使用刘海区显示:public static final int FLAG_NOTCH_SUPPORT=0x00010000;

调用范例参考:

/*刘海屏全屏显示FLAG*/
public static final int FLAG_NOTCH_SUPPORT=0x00010000;
/**
 * 设置应用窗口在华为刘海屏手机使用刘海区
 * @param window 应用页面window对象
 */
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");
    }
}
  1. 华为刘海屏flag动态添加和删除代码:
btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if(isAdd) {//add flag
            isAdd = false;
            NotchSizeUtil.setFullScreenWindowLayoutInDisplayCutout(getWindow());           
            getWindowManager().updateViewLayout(getWindow().getDecorView(),getWindow().getDecorView().getLayoutParams());
        } else{//clear flag
            isAdd = true;
            NotchSizeUtil.setNotFullScreenWindowLayoutInDisplayCutout(getWindow());            
            getWindowManager().updateViewLayout(getWindow().getDecorView(),getWindow().getDecorView().getLayoutParams());
        }
    }
});

VIVO刘海屏判断

public static final int VIVO_NOTCH = 0x00000020;//是否有刘海
public static final int VIVO_FILLET = 0x00000008;//是否有圆角

public static boolean hasNotchAtVivo(Context context) {
    boolean ret = false;
    try {
        ClassLoader classLoader = context.getClassLoader();
        Class FtFeature = classLoader.loadClass("android.util.FtFeature");
        Method method = FtFeature.getMethod("isFeatureSupport", int.class);
        ret = (boolean) method.invoke(FtFeature, VIVO_NOTCH);
    } catch (ClassNotFoundException e) {
        LogUtil.e( "Vivo","hasNotchAtVivo ClassNotFoundException");
    } catch (NoSuchMethodException e) {
        LogUtil.e(  "Vivo","hasNotchAtVivo NoSuchMethodException");
    } catch (Exception e) {
        LogUtil.e(  "Vivo","hasNotchAtVivo Exception");
    } finally {
        return ret;
    }
}

OPPO刘海屏判断

public static boolean hasNotchAtOPPO(Context context) {
     return  context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
}

你可能感兴趣的:(Android,#,Framework)