当前位置:网站首页>API处理Android安全距离
API处理Android安全距离
2022-06-12 08:28:00 【码中之牛】
在Android屏幕的空间中,大部分的区域我们都是可以随意绘制,只有一部分区域是显示的固定内容:
- 状态栏
- 标题栏(ActionBar)
- 页面内容(Content)
- 导航栏
其中标题栏是可选的,除了Material风格的应用应用的并不多,页面内容就是android.R.id.content是Activity的主要内容。
而我们主要需要讨论的就是 状态栏和导航栏,因为这两个区域在不同设备类型,不同的Android版本和不同的厂商下大小和效果是不同的,等等。这些差异无疑增加了我们做页面适配的复杂程度,也更容易出现兼容问题。
在2017年下半年iPhone X的发布,引入了刘海屏设备,导致了蓝绿大厂争相效仿,同时又自成一派,颇有一番百家争鸣之象。
这也导致了一个新的问题 刘海区域适配 ,那时候Android才8.1,并没有API来支持这屏幕上这多出来的一块区域,不过好在大部分设备在定制时刘海和状态栏高度是一致的。
终于在2018年发布的Android 9中Google正式支持了刘海屏,定制了规范约束了设备厂商,减轻了刘海屏适配的差异问题,但是根源问题并没有解决。因为刘海区域的存在,可能会出现页面内容被遮挡,比如:启用页广告跳过按钮被遮挡的问题,导致被应用商店拒掉的风险。
不过好在Android 9中要求刘海设备必须有以下行为:
- 一条边缘最多只能包含一个刘海。
- 一台设备不能有两个以上的刘海。
- 设备的两条较长边缘上不能有刘海。
- 在未设置特殊标志的竖屏模式下,状态栏的高度必须与刘海的高度持平。
- 默认情况下,在全屏模式或横屏模式下,整个刘海区域必须显示黑边。
刘海高度默认是和状态栏高度一致依旧没有变,所以问题又回到了状态栏区域的处理。
正文
所以肯定有同学说了:直接获取状态栏高度不就可以了适配刘海屏了。像这样:
val top = context.getStatusBarHeight()
titleBar.setPadding(0, top, 0, 0)
这么说也没有错,大部分情况下是没有问题的。但是既然官方已经适配刘海屏了,也为我们提供了新的API为什么不用呢:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.decorView.post {
val top = window.decorView.rootWindowInsets?.displayCutout?.safeInsetTop ?: 0
// val bottom = window.decorView.rootWindowInsets?.displayCutout?.safeInsetBottom ?: 0
titleBar.setPadding(0, top, 0, 0)
}
}
上面的方案实际上可以获取上下左右四个方向的安全距离,但大部分情况我们只需要处理顶部就可以了。实际上这已经可以解决我们的问题了,但是还有更好的解决方案方案:
- 添加依赖
implementation 'androidx.core:core:1.7.0'
// 老版本也可以,但是getInsets() API 还没添加
// implementation 'androidx.core:core:1.3.0'
2.使用ViewCompat工具
ViewCompat.setOnApplyWindowInsetsListener(titleBar) {
view: View, insets: WindowInsetsCompat ->
//val top = insets.systemWindowInsetTop // 高版本已经过时,可以用下面的api替换
val stableInsets = insets.getInsets(
WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
titleBar.setPadding(0, stableInsets.top, 0, 0)
return@setOnApplyWindowInsetsListener insets
}
实际上屏幕安全距离,基本上全部围绕这一个API,Google也推荐我们这么做,在很多系统控件都能看到它的影子,比如:AppBarLayout、DrawerLayout、NavigationBarView等等都有用到,内部都是来处理系统安全距离的。
系统栏适配
上面提到了手机有各种系统栏(状态栏、导航栏),如果一个全屏+刘海屏+透明系统栏+屏幕旋转的页面处理这些安全距离就更复杂,比如短视频页,这里先给大家列几条可能出现的问题:
- 没有导航栏或者可以动态隐藏导航栏的设备
导航栏不会旋转的设备(就是导航栏一直在屏幕的一个边,不会跟随屏幕旋转) - 导航栏跟随屏幕旋转的设备(主要是手势导航的设备和一些平板上)
- 刘海在屏幕底部的设备(开发者选项可以开启双刘海模式,设备两个短边都有刘海)
- 底部刘海+导航栏一起显示的设备
- … …
这些所有的问题通过ViewCompat.setOnApplyWindowInsetsListener() 来优雅处理,通过 WindowInsetsCompat.getInsets(type) 可以获取系统的各个栏的大小,我们也可以同时获取多个系统栏的高度,各个距离内部会进行累加,返回一个类似Rect的对象,对应屏幕的左上右下需要插入的距离:
val stableInsets = insets.getInsets(
WindowInsetsCompat.Type.statusBars() or
WindowInsetsCompat.Type.navigationBars() or
WindowInsetsCompat.Type.displayCutout())
然后在对不同位置的控件添加对应的边距。除了上面提到的三种类型的安全距离,还有一些其他的类型,有兴趣的可以自己了解。
其他适配
ViewCompat.setOnApplyWindowInsetsListener()能解决大部分安全距离的问题,但是有一点它是处理不了的,就是 屏幕圆角,这些安全距离的计算是不处理屏幕圆角的,所以如果有圆角要处理那我们就要另辟蹊径了。
好在Android 12中官方添加了对圆角的支持:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val roundedCorner = insets.toWindowInsets()
?.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT)
roundedCorner?.center
}
我用了Pixel4真机发现能获取到数据,但是模拟器获取不到。
除了圆角支持,还有对隐私指示器提供了支持:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val rect = insets.toWindowInsets()?.privacyIndicatorBounds
// 页面控件需要避开这个区域,不然可能会被遮挡
}
隐私指示器的范围,主要是 摄像头和麦克风 使用中状态的指示器边界,如果是录制直播或者相机的页面需要处理这个区域。
除了圆角以外,好像没有找到官方对打孔屏的支持,可能后面会加入对打孔屏的支持吧。
边栏推荐
- 企业上线MES软件的费用真的很贵?
- FDA审查人员称Moderna COVID疫苗对5岁以下儿童安全有效
- MYSQL中的调用存储过程,变量的定义,
- 智能制造的时代,企业如何进行数字化转型
- X64dbg debugging exception_ ACCESS_ VIOLATION C0000005
- Only use MES as a tool? Looks like you missed the most important thing
- Learning notes (1): live broadcast by Dr. Lu Qi - face up to challenges and grasp entrepreneurial innovation opportunities - face up to challenges and grasp entrepreneurial innovation opportunities -1
- js中的正则表达式
- FPGA generates 720p video clock
- Lock mechanism in MySQL
猜你喜欢

Figure neural network makes Google maps more intelligent

Ankerui fire emergency lighting and evacuation indication system

(P25-P26)基于非范围的for循环、基于范围的for循环需要注意的3个细节

Production scheduling status of manufacturing enterprises and solutions of APS system

Centos8 installing MySQL 8.0 (upper)
![Easyexcel exports excel tables to the browser, and exports excel through postman test [introductory case]](/img/ca/0e2bd54a842a393231ec6db5ab02c2.png)
Easyexcel exports excel tables to the browser, and exports excel through postman test [introductory case]

Py&GO编程技巧篇:逻辑控制避免if else

Hands on deep learning -- weight decay and code implementation

【新规划】

How to understand the production scheduling of APS system?
随机推荐
千万别把MES只当做工具,不然会错过最重要的东西
MES helps enterprises to transform intelligently and improve the transparency of enterprise production
Hands on deep learning -- discarding method and its code implementation
Why should enterprises implement MES? What are the specific operating procedures?
Ankerui fire emergency lighting and evacuation indication system
记Date类型的一次踩坑
At present, MES is widely used. Why are there few APS scheduling systems? Why?
(P17-P18)通过using定义基础类型和函数指针别名,使用using和typedef给模板定义别名
电气火灾探测器对各用电回路进行实时监控
对企业来讲,MES设备管理究竟有何妙处?
Hypergeometric cumulative distribution test overlap
Production scheduling status of manufacturing enterprises and solutions of APS system
Installation series of ROS system (I): installation steps
报错:文件夹在另一个程序中打开无法删除怎么办
Map the world according to the data of each country (take the global epidemic as an example)
Hands on learning and deep learning -- simple implementation of linear regression
Is it really expensive for enterprises to launch MES software?
vm虚拟机中使用NAT模式特别说明
企业为什么要实施MES?具体操作流程有哪些?
FDA reviewers say Moderna covid vaccine is safe and effective for children under 5 years of age