无需再怨恨“刘海屏”了,因为适配十分简单
Linux编程 点击右侧关注,免费入门到精通!
作者丨王英豪
https://www.jianshu.com/p/c9e710a9fa35
网上关于刘海屏适配的文章不少,可讲清楚的却没几篇,大多是拷贝文档、长篇大论,甚至热情的贴图告诉你什么是刘海屏,到最后你仍不确定到底是怎样的一个适配方案,才能让你的 app 真正的适配所有的刘海屏机型。
看到这篇文章你就无需再怨恨各大厂商的跟风“刘海”了,因为刘海屏的适配十分简单。
ok,废话说完了,开始适配。
首先要清楚的是哪些界面需要适配刘海屏:
有状态栏的界面:刘海区域会显示状态栏,无需适配
全屏界面:刘海区域可能遮挡内容,需要适配
如果你的应用里所有界面都有状态栏,那么恭喜你,你不用做任何操作,状态栏就那么自然的显示在刘海区域,毫无违和,刘海屏已适配完毕,可以点叉出去了。
不幸的是,你的应用中很大几率会有全屏界面,所谓的刘海屏适配,也正是针对这些全屏界面。
如果你什么都不做,默认规则不允许全屏界面内容显示到刘海区域,即刘海屏区域会保留一条黑边,你的全屏界面会在刘海下方展示,这看起来好像也是可以接受的,然后你竟说服产品达成共识,“无为而治”才是最强大的刘海屏适配方案!
但有些手机厂商(譬如oppo)不开心了,我辛辛苦苦研发的刘海屏手机,你们这些开发者竟直接放弃刘海区域!然后就在你的全屏界面下方加了一条提示:“全屏显示”,当用户点击开启后,强行把你的全屏界面显示到刘海区域,然后一切都乱套了...
嗯~ “无为而治”行不通。
只能允许全屏界面内容显示到刘海区域了,参考各大厂商的适配文档,我们可以知道如何允许,比如华为机型只需在 AndroidManifest 中配置:
<meta-data android:name="android.notch_support" android:value="true" />
配置后,华为机型上的全屏界面就会显示到刘海区域了,但这个刘海,是可能挡住我们全屏界面中的内容的。这时需要将全屏界面中的视图元素适当下移,保证不会被刘海遮挡住,就 ok 了。
这里我们搞清楚:允许全屏界面内容显示到刘海区域的机型,才需要将全屏界面中的视图元素适当下移。
比如若只允许华为机型全屏界面内容显示到刘海区域,那只有华为的刘海屏机型才需要将全屏界面中的视图元素适当下移,其他厂商的刘海屏机型则不需要下移。
如果允许华为、小米、oppo、vivo 全屏界面内容显示到刘海区域,那么华为、小米、oppo、vivo 刘海屏机型需要将全屏界面中的视图元素适当下移。
另外也不一定要通过全屏界面中的视图元素适当下移方式来适配刘海屏,如果产品形态允许的话,你也可以让该界面显示状态栏啊。
至此刘海屏适配完毕,是不是很简单!?
最后代码奉上,拿走不谢:
1、允许全屏界面内容显示到刘海区域配置:
<!--允许绘制到oppo、vivo刘海屏机型的刘海区域 --><meta-data android:name="android.max_aspect" android:value="2.2" />
<!-- 允许绘制到华为刘海屏机型的刘海区域 --><meta-data android:name="android.notch_support" android:value="true" />
<!-- 允许绘制到小米刘海屏机型的刘海区域 --><meta-data android:name="notch.config" android:value="portrait" />
上面在 AndroidManifest 的配置在 Android 9.0 之前有效,9.0 系统针对刘海屏制定了新的 api,默认保留一条黑边,即不允许绘制到刘海区域。所以如果你还没有适配 Android 9.0,那在判断是否是允许全屏界面内容显示到刘海区域的刘海屏机型时,就要加上版本判断。
2、判断是否是允许全屏界面内容显示到刘海区域的刘海屏机型:
public class CutoutUtil {
private static Boolean sAllowDisplayToCutout;
/** * 是否为允许全屏界面显示内容到刘海区域的刘海屏机型(与AndroidManifest中配置对应) */ public static boolean allowDisplayToCutout() { if (sAllowDisplayToCutout == null) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) { // 9.0系统全屏界面默认会保留黑边,不允许显示内容到刘海区域 return sAllowDisplayToCutoutDevice = false; } Context context = App.get(); if (hasCutout_Huawei(context)) { return sAllowDisplayToCutout = true; } if (hasCutout_OPPO(context)) { return sAllowDisplayToCutout = true; } if (hasCutout_VIVO(context)) { return sAllowDisplayToCutout = true; } if (hasCutout_XIAOMI(context)) { return sAllowDisplayToCutout = true; } return sAllowDisplayToCutout = false; } else { return sAllowDisplayToCutout; } }
/** * 是否是华为刘海屏机型 */ @SuppressWarnings("unchecked") private static boolean hasCutout_Huawei(Context context) { if (!Build.MANUFACTURER.equalsIgnoreCase("HUAWEI")) { return false; } try { ClassLoader cl = context.getClassLoader(); Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil"); if (HwNotchSizeUtil != null) { Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen"); return (boolean) get.invoke(HwNotchSizeUtil); } return false; } catch (Exception e) { return false; } }
/** * 是否是oppo刘海屏机型 */ @SuppressWarnings("unchecked") private static boolean hasCutout_OPPO(Context context) { if (!Build.MANUFACTURER.equalsIgnoreCase("oppo")) { return false; } return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism"); }
/** * 是否是vivo刘海屏机型 */ @SuppressWarnings("unchecked") private static boolean hasCutout_VIVO(Context context) { if (!Build.MANUFACTURER.equalsIgnoreCase("vivo")) { return false; } try { ClassLoader cl = context.getClassLoader(); @SuppressLint("PrivateApi") Class ftFeatureUtil = cl.loadClass("android.util.FtFeature"); if (ftFeatureUtil != null) { Method get = ftFeatureUtil.getMethod("isFeatureSupport", int.class); return (boolean) get.invoke(ftFeatureUtil, 0x00000020); } return false; } catch (Exception e) { return false; } }
/** * 是否是小米刘海屏机型 */ @SuppressWarnings("unchecked") private static boolean hasCutout_XIAOMI(Context context) { if (!Build.MANUFACTURER.equalsIgnoreCase("xiaomi")) { return false; } try { ClassLoader cl = context.getClassLoader(); @SuppressLint("PrivateApi") Class SystemProperties = cl.loadClass("android.os.SystemProperties"); 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] = "ro.miui.notch"; params[1] = 0; return (Integer) getInt.invoke(SystemProperties, params) == 1; } catch (Exception e) { return false; } }
}
上面提到,不一定要通过全屏界面中的视图元素适当下移方式来适配刘海屏,如果产品形态允许的话,也可以让该界面显示状态栏。
显示状态栏的方案是较为通用简单的,或者说,在一个应用中,一些全屏界面往往是允许使用显示状态栏的方案来适配的,如果你考虑使用这种方案,那便会是这种效果:
在你的应用中,你期望某些全屏界面在刘海屏机型上必须全屏展示,那你就自行将界面元素适当下移,从而避免被刘海遮挡;而某些全屏界面不是非要全屏显示,允许在刘海屏机型显示状态栏,那就通过显示状态栏的方式,从而避免被刘海遮挡。
为了实现这种效果,我们需要标记区分哪些界面必须全屏展示、哪些界面允许显示状态栏。这里提供一种实现方式,让允许显示状态栏的界面 Activity 继承一个接口,比如:
public interface CutoutAdapt {}
然后在 ActivityLifecycleCallbacks 回调,统一适配允许通过显示状态栏的全屏界面:
@Overridepublic void onActivityStarted(Activity activity) { // 如果是允许全屏显示到刘海屏区域的刘海屏机型 if (CutoutUtil.allowDisplayToCutout()) { if (isFullScreen(activity)) { // 如果允许通过显示状态栏方式适配刘海屏 if (activity instanceof CutoutAdapt) { // 显示状态栏 StatusBarUtil.showStatusbar(activity.getWindow()); } else { // 需自行将该界面视图元素下移,否则可能会被刘海遮挡 } } else { // 非全屏界面无需适配刘海屏 } }}
推荐↓↓↓
长
按
关
注
?【16个技术公众号】都在这里!
涵盖:程序员大咖、源码共读、程序员共读、数据结构与算法、黑客技术和网络安全、大数据科技、编程前端、Java、Python、Web编程开发、Android、iOS开发、Linux、数据库研发、幽默程序员等。
万水千山总是情,点个 “ 好看” 行不行
无需再怨恨“刘海屏”了,因为适配十分简单相关推荐
- android屏幕适配的五种方式_讲一讲Android 9.0系统的新特性,对刘海屏设备进行适配...
黑客技术点击右侧关注,了解黑客的世界! Java开发进阶点击右侧关注,掌握进阶之路! Python开发点击右侧关注,探讨技术话题!作者丨郭霖来源丨郭霖(guolin_blog) 其实Android 9 ...
- android刘海屏之终极适配
前言:作为安卓开发,也得承认苹果设计一直在引领潮流,所以自从 iPhone X 发布之后,"刘海屏" 就一直被热议,作为我自己必须先吐槽一下,真没觉得刘海屏好看.但是作为苦逼的开发 ...
- Android 刘海屏全面屏适配
参考链接: https://blog.csdn.net/u011494285/article/details/86681405 API >= 24 (Android 7.0) 以上会自动适配全面 ...
- 解决OPPO系统在Android10魔改刘海屏的额外适配
最近我们的应用在一部oppo reno3 5g(Android 10)手机上适配存在问题. 先放一些官方文档吧:) https://developer.android.com/reference/an ...
- 简洁明了的刘海屏适配方案
网上关于刘海屏适配的文章不少,可讲清楚的却没几篇,大多是拷贝文档.长篇大论,甚至热情的贴图告诉你什么是刘海屏,到最后你仍不确定到底是怎样的一个适配方案,才能让你的 app 真正的适配所有的刘海屏机型. ...
- Android刘海屏适配全方案(华为、小米、Vivo、Oppo)
前言 目前市面上的刘海屏和水滴屏手机越来越多了,颜值方面是因人而异,有的人觉得很好看,也有人觉得丑爆了,我个人觉得是还可以.但是作为移动开发者来说,这并不是一件好事,越来越多异形屏手机的出现意味着我们 ...
- android刘海屏高度适配,Android刘海屏的适配
这里主要是介绍一下Android P中刘海屏的适配以及Android P之前的适配.为什么要分开呢?因为Android P之前官方还没提供API来进行适配,都是由各家厂商来提供适配方案的. 1.And ...
- Android 刘海屏适配全攻略
这里主要是介绍一下Android P中刘海屏的适配以及Android P之前的适配.为什么要分开呢?因为Android P之前官方还没提供API来进行适配,都是由各家厂商来提供适配方案的. 2.And ...
- android获取刘海屏状态栏高度,Android刘海屏全面屏底部导航栏的适配
关于Android状态栏和虚拟导航栏的适配,文章:https://blog.csdn.net/leogentleman/article/details/54566319 讲的很不错. 状态栏的适配: ...
最新文章
- 机器学习与深度学习常见面试问题与答案
- 1、Hello World
- 云机搭jdk1.8和apache-tomcat
- Python 【快手】短视频的自动上传与发布实例演示,同时支持抖音、哔哩哔哩、小红书、微视、西瓜视频、微信视频号等平台的视频自动化同步发布
- jira使用教程pdf_需要申请项目?需要开通权限?需要创建流程?刚需教程安排上了!...
- string类的各种函数用法
- koa2 mysql 中间件_Koa2 和 Express 中间件对比
- T-SQL查询-逻辑查询处理
- SVM中的间隔最大化
- Illustrator 教程,如何在 Illustrator 中变换图稿?
- linux内核之字符设备驱动图解
- 新的文档类型定义模型带来的问题--javascirpt/CSS
- flashfxp连接centos7失败原因之一
- 几款常用UML建模工具介绍
- (10)python日志收集
- 差点以为是本人!这个3D人体生成模型厉害了,还能自己改POSE
- el-table点击单元格自动聚焦可编辑,且失去焦点即修改成功的实现方法
- 产品生命周期管理PLM技术研究
- 简历解析步骤(第二步)技术与实现(6)识文字,做分类:婚姻状态 、出生日期 、 户口地址 、 籍贯地址
- 目前住院病人主要由护士护理