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描述:应用通过增加华为自定义的刘海屏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"); }}
- 接口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"); }}
- 华为刘海屏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核心分析(18)-----Android电话系统之RIL-Java
- 安卓JNI入门
- 【转】Android(安卓)JNI实例
- Android读书笔记-2 序列化
- 关于Android中aidl的关键词in,out,inout的探索
- Android(安卓)序列化
- android 播放器 实现场景搜索 调研
- Android(安卓)Binder 分析——匿名共享内存(Ashmem)
- Android下图形系统