内容简介:屏幕的正上方居中位置(上图黑色区域)会被挖掉一个孔,屏幕被挖掉的区域无法正常显示内容,这种类型的屏幕就是刘海屏,也有其他叫法:挖孔屏、凹凸屏等等,为便于说明,后文提到的「刘海屏」都同时指代上图两种屏幕。Apple一直在引领设计的潮流,自从 iPhone X 发布之后,”刘海屏” 就一直存在争议,本以为是一个美丽的错误(Bug),却造就了一时间“刘海屏”的模仿潮,由于Android在9.0之前没有给出官方指导,所以出现了各个厂商自扫门前雪的状况。本文主要讲述Android 8.0在各个手机上的适配方案,包括小
什么是刘海屏
屏幕的正上方居中位置(上图黑色区域)会被挖掉一个孔,屏幕被挖掉的区域无法正常显示内容,这种类型的屏幕就是刘海屏,也有其他叫法:挖孔屏、凹凸屏等等,为便于说明,后文提到的「刘海屏」都同时指代上图两种屏幕。Apple一直在引领设计的潮流,自从 iPhone X 发布之后,”刘海屏” 就一直存在争议,本以为是一个美丽的错误(Bug),却造就了一时间“刘海屏”的模仿潮,由于Android在9.0之前没有给出官方指导,所以出现了各个厂商自扫门前雪的状况。本文主要讲述Android 8.0在各个手机上的适配方案,包括小米、Oppo/ViVo、华为、三星等主流机型,并在文末提及Android P统一适配方案。
小米 MIUI Notch 屏适配说明
目前已上市的小米 Notch 设备(俗称刘海屏手机)如下,其宽度、高度和形状均略有差异
机型 |
model |
device |
分辨率 |
Notch 高度 |
Notch 宽度 |
DPI |
小米8 |
MI 8 |
dipper |
1080*2248 |
89 |
560 |
440 |
小米8 SE |
MI 8 SE |
sirius |
1080*2244 |
85 |
540 |
440 |
小米8 透明探索版 |
MI 8 Explorer Edition |
ursa |
1080*2248 |
89 |
560 |
440 |
小米8 屏幕指纹版 |
MI 8 UD |
equuleus |
1080*2248 |
89 |
560 |
440 |
小米8 青春版 |
MI8Lite |
platina |
1080*2280 |
82 |
296 |
440 |
小米POCO F1 |
POCO F1 |
beryllium |
1080*2246 |
86 |
588 |
440 |
红米6 Pro |
Redmi 6 Pro |
sakura |
1080*2280 |
89 |
352 |
440 |
注:以上设备,由于MIUI调整了DPI值,因此DP值与像素值的转换关系是 1dp = 2.75 px 。
如何判断设备为 Notch 机型
系统增加了 property ro.miui.notch,值为1时则是 Notch 屏手机。
SystemProperties.getInt("ro.miui.notch", 0) == 1;复制代码
如何获取 Notch / 凹口 / 刘海 的高度和宽度(截至2018.6.26)
MIUI 10 新增了获取刘海宽和高的方法,需升级至8.6.26开发版及以上版本。
以下是获取当前设备刘海高度的方法:
int resourceId = context.getResources().getIdentifier("notch_height", "dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); }复制代码
以下是获取当前设备刘海宽度的方法:
int resourceId = context.getResources().getIdentifier("notch_width", "dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); }复制代码
注意上述获取宽高的方法仅限于2018.6.26的以上的版本,那么如何判断小米的MIUI 的版本 ?
/** * 判断是否大于 1529942400 ,2018.6.26 转为毫秒是 1529942400 ,MIUI10 的版本Version codetime * @return */ public boolean isGreaterMIUI10() { return (Long.parseLong(checkMIUI()) >= 1529942400); } public static String checkMIUI() { String versionCode = ""; String manufacturer = Build.MANUFACTURER; String model = Build.MODEL; Logger.d(TAG,"Build.MANUFACTURER = " + manufacturer + " ,Build.MODEL = " + Build.MODEL); if (!TextUtils.isEmpty(manufacturer) && manufacturer.equals("Xiaomi")) { versionCode = getSystemProperty("ro.miui.version.code_time"); } return versionCode; }复制代码
2018.6.26的以下的版本参考1.3.
状态栏高度获取方法
由于 Notch 设备的状态栏高度与正常机器不一样,因此在需要使用状态栏高度时,不建议写死一个值,而应该改为读取系统的值。
以下是获取当前设备状态栏高度的方法:
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); }复制代码
Oppo 凹形屏适配说明
如何判断设备为刘海屏 机型
本次凹形屏规格的机型型号:
PAAM00
PAAT00
PACM00
PACT00
CPH1831
CPH1833
上述机型的屏幕规格完全相同,不需分别做差异化处理,统一适配即可。
context.getPackageManager().hasSystemFeature(“com.oppo.feature.screen.heteromorphism”),返回 true为凹形屏 ,可识别OPPO的手机是否为凹形屏。
publicstaticbooleanhasNotchOPPO(Context context){ return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism"); }复制代码
如何获取 Notch / 凹口 / 刘海 的高度和宽度
OPPO不提供接口获取刘海尺寸,目前其有刘海屏的机型尺寸规格都是统一的。
采用宽度为1080px, 高度为2280px的圆弧显示屏。 屏幕顶部凹形区域不能显示内容,宽度为324px, 高度为80px。
图左:全屏显示示意图,绿色区域为可显示区域
图右:16:9显示示意图,绿色区域为可显示区域
VIVO 全面屏应用适配指南
如何判断是刘海屏机型
publicstaticfinalint VIVO_NOTCH = 0x00000020;//是否有刘海publicstaticfinalint VIVO_FILLET = 0x00000008;//是否有圆角publicstaticbooleanhasNotchAtVivo(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) { Log.e("Notch", "hasNotchAtVivo ClassNotFoundException"); } catch (NoSuchMethodException e) { Log.e("Notch", "hasNotchAtVivo NoSuchMethodException"); } catch (Exception e) { Log.e("Notch", "hasNotchAtVivo Exception"); } finally { return ret; } }复制代码
如何获取 Notch / 凹口 / 刘海 的高度和宽度
vivo不提供接口获取刘海尺寸,目前vivo的刘海宽为100dp,高为27dp。同样建议使用2.2中状态栏高度的方式适配。
华为 刘海屏手机安卓O版本适配指导
华为的文档是比较标准的,更为贴近Android P官方提供的方案。
如何判断是否有刘海屏
类文件 | 接口 | 接口说明 |
com.huawei.android.util.HwNotchSizeUtil | public static boolean hasNotchInScreen() | 是否是刘海屏手机: true:是刘海屏;false:非刘海屏。 |
publicstaticbooleanhasNotchAtHuawei(Context context){ boolean ret = false; try { ClassLoader classLoader = context.getClassLoader(); Class HwNotchSizeUtil = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil"); Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen"); ret = (boolean) get.invoke(HwNotchSizeUtil); } catch (ClassNotFoundException e) { Log.e("Notch", "hasNotchAtHuawei ClassNotFoundException"); } catch (NoSuchMethodException e) { Log.e("Notch", "hasNotchAtHuawei NoSuchMethodException"); } catch (Exception e) { Log.e("Notch", "hasNotchAtHuawei Exception"); } finally { return ret; } }复制代码
如何获取 刘海 的高度和宽度
类文件 | 接口 | 接口说明 |
com.huawei.android.util.HwNotchSizeUtil | public static int[] getNotchSize() | 获取刘海尺寸:width、height int[0]值为刘海宽度 int[1]值为刘海高度。 |
//获取刘海尺寸:width、height//int[0]值为刘海宽度 int[1]值为刘海高度publicstaticint[] getNotchSizeAtHuawei(Context context) { int[] ret = newint[]{0, 0}; try { ClassLoader cl = context.getClassLoader(); Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil"); Method get = HwNotchSizeUtil.getMethod("getNotchSize"); ret = (int[]) get.invoke(HwNotchSizeUtil); } catch (ClassNotFoundException e) { Log.e("Notch", "getNotchSizeAtHuawei ClassNotFoundException"); } catch (NoSuchMethodException e) { Log.e("Notch", "getNotchSizeAtHuawei NoSuchMethodException"); } catch (Exception e) { Log.e("Notch", "getNotchSizeAtHuawei Exception"); } finally { return ret; } }复制代码
三星
/** * 三星手机SM-G8870 刘海屏适配 * */ @RequiresApi(api = Build.VERSION_CODES.O) public void getSamsungCutOutInfo() { try { final View decorView = mActivity.getWindow().getDecorView(); WindowInsets windowInsets = decorView.getRootWindowInsets(); WindowInsetsWrapper wrapper = new WindowInsetsWrapper(windowInsets); DisplayCutoutWrapper mLastDisplayCutoutWrapper = wrapper.getDisplayCutoutWrapper(); if (mLastDisplayCutoutWrapper == null) { isSamsungCutOutMode = false; return; } List<Rect> boundingRects = mLastDisplayCutoutWrapper.getBoundingRects(); if (boundingRects == null || boundingRects.size() == 0) { Logger.d(TAG, "is not notch screen"); isSamsungCutOutMode = false; } else { isSamsungCutOutMode = true; Logger.d(TAG, "Top=" + mLastDisplayCutoutWrapper.getSafeInsetTop()); Logger.d(TAG, "Bottom=" + mLastDisplayCutoutWrapper.getSafeInsetBottom()); Logger.d(TAG, "Left=" + mLastDisplayCutoutWrapper.getSafeInsetLeft()); Logger.d(TAG, "Right=" + mLastDisplayCutoutWrapper.getSafeInsetRight()); mSamsungSafeInsetHeight = mLastDisplayCutoutWrapper.getSafeInsetLeft() + mLastDisplayCutoutWrapper.getSafeInsetTop(); } } catch (Exception e) { e.printStackTrace(); } }复制代码
谷歌P版本刘海屏适配方案
特性介绍
谷歌称刘海屏为凹口屏以及屏幕缺口支持, 下面的内容摘自: developer.android.com/preview/fea…
Android P 支持最新的全面屏以及为摄像头和扬声器预留空间的凹口屏幕。 通过全新的 DisplayCutout 类,可以确定非功能区域的位置和形状,这些区域不应显示内容。 要确定这些凹口屏幕区域是否存在及其位置,请使用 getDisplayCutout() 函数。
1. 全新的窗口布局属性 layoutInDisplayCutoutMode 让您的应用可以为设备凹口屏幕周围的内容进行布局。 您可以将此属性设为下列值之一:
(1)LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
(2)LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
(3)LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
2. 您可以按如下方法在任何运行 Android P 的设备或模拟器上模拟屏幕缺口:
(1)启用开发者选项。
(2)在 Developer options 屏幕中,向下滚动至 Drawing 部分并选择 Simulate a display with a cutout。
(3)选择凹口屏幕的大小。
注意:
我们建议您通过使用运行 Android P 的设备或模拟器测试凹口屏幕周围的内容显示。
接口介绍
1. 获取刘海尺寸相关接口:
developer.android.com/reference/a…
所属类 | 方法 | 接口说明 |
android.view.DisplayCutout | List<Rect> getBoundingRects() | 返回Rects的列表,每个Rects都是显示屏上非功能区域的边界矩形。设备的每个短边最多只有一个非功能区域,而长边上则没有。 |
android.view.DisplayCutout | int getSafeInsetBottom() | 返回安全区域距离屏幕底部的距离,单位是px。 |
android.view.DisplayCutout | int getSafeInsetLeft () | 返回安全区域距离屏幕左边的距离,单位是px。 |
android.view.DisplayCutout | int getSafeInsetRight () | 返回安全区域距离屏幕右边的距离,单位是px。 |
android.view.DisplayCutout | int getSafeInsetTop () | 返回安全区域距离屏幕顶部的距离,单位是px。 |
2. 设置是否延伸到刘海区显示接口:
developer.android.com/reference/a…
类 | 属性 | 属性说明 |
android.view.WindowManager.LayoutParams | int layoutInDisplayCutoutMode | 默认值: LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 其他可能取值: LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER |
developer.android.com/reference/a…
类 | 常量 | 常量说明 |
android.view.WindowManager.LayoutParams | int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT | 只有当DisplayCutout完全包含在系统状态栏中时,才允许窗口延伸到DisplayCutout区域显示。 |
android.view.WindowManager.LayoutParams | int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER | 该窗口决不允许与DisplayCutout区域重叠。 |
android.view.WindowManager.LayoutParams | int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES | 该窗口始终允许延伸到屏幕短边上的DisplayCutout区域。 |
参考实现代码
1. 设置使用刘海区显示代码:
getSupportActionBar().hide(); getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); //设置页面全屏显示 WindowManager.LayoutParams lp = getWindow().getAttributes(); lp.layoutInDisplayCutoutMode = windowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; //设置页面延伸到刘海区显示 getWindow().setAttributes(lp);复制代码
注意:如果需要应用的布局延伸到刘海区显示,需要设置SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN。
属性:
不使用SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 使用SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
布局无法延伸到刘海显示 布局可以正真延伸到刘海区显示
2. 获取刘海屏安全显示区域和刘海尺寸信息:
contentView = getWindow().getDecorView().findViewById(android.R.id.content).getRootView(); contentView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @Override public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) { DisplayCutout cutout = windowInsets.getDisplayCutout(); if (cutout == null) { Log.e(TAG, "cutout==null, is not notch screen");//通过cutout是否为null判断是否刘海屏手机 } else { List<Rect> rects = cutout.getBoundingRects(); if (rects == null || rects.size() == 0) { Log.e(TAG, "rects==null || rects.size()==0, is not notch screen"); } else { Log.e(TAG, "rect size:" + rects.size());//注意:刘海的数量可以是多个 for (Rect rect : rects) { Log.e(TAG, "cutout.getSafeInsetTop():" + cutout.getSafeInsetTop() + ", cutout.getSafeInsetBottom():" + cutout.getSafeInsetBottom() + ", cutout.getSafeInsetLeft():" + cutout.getSafeInsetLeft() + ", cutout.getSafeInsetRight():" + cutout.getSafeInsetRight() + ", cutout.rects:" + rect ); } } } return windowInsets; } });复制代码
3. 说明:
(1)通过windowInsets.getDisplayCutout()是否为null判断是否刘海屏手机,如果为null为非刘海屏:
Line 6203: 05-24 11:16:46.766 11036 11036 E Cutout_test: cutout==null, is not notch screen复制代码
(2)如果是刘海屏手机可以通过接口获取刘海信息:
Line 6211: 05-24 11:11:16.839 10733 10733 E Cutout_test: cutout.getSafeInsetTop():126, cutout.getSafeInsetBottom():0, cutout.getSafeInsetLeft():0, cutout.getSafeInsetRight():0, cutout.rects:Rect(414, 0 - 666, 126)复制代码
(3)刘海个数可以是多个:
Line 6291: 05-24 11:27:04.517 11036 11036 E Cutout_test: rect size:2 Line 6292: 05-24 11:27:04.517 11036 11036 E Cutout_test: cutout.getSafeInsetTop():84, cutout.getSafeInsetBottom():84, cutout.getSafeInsetLeft():0, cutout.getSafeInsetRight():0, cutout.rects:Rect(351, 0 - 729, 84) Line 6293: 05-24 11:27:04.517 11036 11036 E Cutout_test: cutout.getSafeInsetTop():84, cutout.getSafeInsetBottom():84, cutout.getSafeInsetLeft():0, cutout.getSafeInsetRight():0, cutout.rects:Rect(351, 1836 - 729, 1920)复制代码
参考文档
1、小米 MIUI Notch 屏适配说明
2、Oppo凹形屏适配说明
3、VIVO全面屏应用适配指南
4、华为 刘海屏手机安卓O版本适配指导
5、Google官网 developer.android.com/preview/fea…
以上所述就是小编给大家介绍的《Android 刘海屏适配》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- flutter 屏幕尺寸适配 字体大小适配
- 前端适配:移动端/web端适配方案
- iOS 关于全面屏适配的方案及UI在不同尺寸下适配方案
- iOS 关于全面屏适配的方案及UI在不同尺寸下适配方案
- 【移动端适配】用vw、vh+媒体查询打造最完美的移动端适配方案
- Rem 等比适配始末
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HEX CMYK 转换工具
HEX CMYK 互转工具
HEX HSV 转换工具
HEX HSV 互换工具