Android 11----瀑布屏初识
文章目录
Android 11----瀑布屏初识
声明
博客地址:http://blog.csdn.net/luzhenrong45
瀑布屏简介
最近开始适配Android R,因此需要对Android R上的一些新特性功能进行大致了解,其中就有包括Google对瀑布屏的原生支持。瀑布屏手机是指拥有超高曲率的曲面屏手机,一种无边框的全面屏,被视为刘海屏的变体。目前国内华米OV都推出了自家的瀑布屏手机产品,比如华为Mate 40 Pro、vivo NEX 3、小米10等,瀑布屏可以说是2020下半年旗舰手机的标配特性之一了。
瀑布屏系统配置
Android 11 开始官方支持瀑布屏,Google将瀑布屏视为刘海屏的一种变体类型,首先回顾下刘海屏的系统配置方法,Android P版本开始原生支持刘海屏,有以下几种:
- 顶部中间刘海屏:刘海屏位于顶部边缘的中间位置,这种刘海屏比较常见。
- 边角刘海屏:刘海屏位于边角处或稍微偏离中心的位置
- 底部刘海屏:刘海屏位于底部
- 双刘海屏:一个刘海屏位于顶部,一个位于底部
- 水滴屏:可以理解为顶部中间刘海屏的一种,只不过刘海区域类似于水滴形状,宽度较窄
- 打孔屏:在屏幕一角圆孔型挖孔,相机模块位于此处,因此屏幕边缘不会被凹口触及
要在设备上实现刘海屏,一般需要在系统代码配置以下几个值:
配置项 | 说明 |
---|---|
quick_qs_offset_height |
定义“快捷设置”面板的上外边距。时钟和电池图标显示在该面板上方的空间。 在 values-land 中,将此值设置为 status_bar_height_landscape,在纵屏模式下,将此值设置为默认值 48dp 或刘海屏高度(以较大者为准)。可以根据需要选择高于刘海屏的高度。 |
quick_qs_total_height |
展开通知栏时,“超快设置”面板(收起的“快捷设置”面板)的总高度(其中包括包含时钟图标的面板上方的空间)。 受“快捷设置”面板的布局方式限制,“超快设置”面板(包括偏移量)的总高度必须是静态已知的,因此必须由同一增量 quick_qs_offset_height 调整此值。在 Values-land 中,此值默认为 152dp,在纵屏模式下,此值默认为 176dp。 |
status_bar_height_portrait |
从框架的角度而言,状态栏的默认高度。 在大多数设备上,此值默认为24dp。如果设备上有刘海屏,则将此值设置为刘海屏的高度。可以根据需要选择高于刘海屏的高度。 |
status_bar_height_landscape |
状态栏在横屏模式下的高度。由于仅支持在设备的短边上显示刘海屏,因此此值始终是未经更改的状态栏高度。 在没有刘海屏的设备上,此值等同于 status_bar_height_portrait。如果设备上有刘海屏,则将此值保留为默认的状态栏高度。 |
config_mainBuiltInDisplayCutout |
用于定义刘海屏形状的路径。这是一个可由 android.util.PathParser 解析的字符串,并且是告知系统刘海屏大小和形状的方式。 可在路径中指定 @dp 以便模拟针对不同设备的形状。由于实际的刘海屏具有精确的像素尺寸,因此在定义硬件刘海屏的路径时,请勿使用 @dp 指定符。 |
config_fillMainBuiltinDisplayCutout |
一个确定是否在软件中绘制刘海屏路径(在上文中进行了定义)的布尔值。可用于模拟刘海屏,或填充实际刘海屏,以实现抗锯齿。如果为 true,则系统会以黑色填充 config_mainBuiltInDisplayCutout。 |
比如开发者选项中,模拟水滴屏的系统配置:
【frameworks/base/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml】
<string translatable="false" name="config_mainBuiltInDisplayCutout">
M 0,0
L -24, 0
L -21.9940446283, 20.0595537175
C -21.1582133885, 28.4178661152 -17.2, 32.0 -8.8, 32.0
L 8.8, 32.0
C 17.2, 32.0 21.1582133885, 28.4178661152 21.9940446283, 20.0595537175
L 24, 0
Z
@dp
</string>
<string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
<!-- Whether the display cutout region of the main built-in display should be forced to
black in software (to avoid aliasing or emulate a cutout that is not physically existent).
-->
<bool name="config_fillMainBuiltInDisplayCutout">true</bool>
<!-- Height of the status bar -->
<dimen name="status_bar_height_portrait">48dp</dimen>
<dimen name="status_bar_height_landscape">28dp</dimen>
<!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) -->
<dimen name="quick_qs_offset_height">48dp</dimen>
<!-- Total height of QQS (quick_qs_offset_height + 128) -->
<dimen name="quick_qs_total_height">176dp</dimen>
另外,为了确保刘海屏不会对应用造成负面影响(比如刘海区域影响了应用内容显示或响应操作等),需要确保:
- 在竖屏模式下,状态栏的高度至少与刘海屏的高度持平
- 在全屏模式和横屏模式下,刘海屏区域必须显示遮幅式黑边
刘海屏详细介绍可查阅 Android官方文档
Android 11版本对刘海屏的设备类型支持进行了扩展,开始支持瀑布屏,但截止目前官方文档并没有介绍瀑布屏的具体系统配置方法。通过走读刘海屏(DisplayCutout)相关系统源码,发现Android 11.0在10.0基础上新增一些代码,以实现支持瀑布屏参数的配置和获取。
【frameworks/base/core/java/android/view/DisplayCutout.java】
private static Insets loadWaterfallInset(Resources res) {
return Insets.of(
res.getDimensionPixelSize(R.dimen.waterfall_display_left_edge_size),
res.getDimensionPixelSize(R.dimen.waterfall_display_top_edge_size),
res.getDimensionPixelSize(R.dimen.waterfall_display_right_edge_size),
res.getDimensionPixelSize(R.dimen.waterfall_display_bottom_edge_size));
}
非瀑布屏参数(系统默认配置)
【frameworks/base/core/res/res/values/dimens.xml】
<!-- For Waterfall Display -->
<dimen name="waterfall_display_left_edge_size">0px</dimen>
<dimen name="waterfall_display_top_edge_size">0px</dimen>
<dimen name="waterfall_display_right_edge_size">0px</dimen>
<dimen name="waterfall_display_bottom_edge_size">0px</dimen>
瀑布屏专用的配置参数, 参考如下:
【frameworks/base/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml】
<dimen name="waterfall_display_left_edge_size">20dp</dimen> <!-- 瀑布屏左曲边弧长 -->
<dimen name="waterfall_display_top_edge_size">0dp</dimen>
<dimen name="waterfall_display_right_edge_size">20dp</dimen> <!--瀑布屏右曲边弧长-->
<dimen name="waterfall_display_bottom_edge_size">0dp</dimen>
从字面意义上不难理解这4个配置项分别用于手机屏幕四边的曲边弧长配置。一般来说,瀑布屏手机只需要配置左右曲边弧长,即 R.dimen.waterfall_display_left_edge_size 和 R.dimen.waterfall_display_left_edge_size。(当然,不排除手机厂商后续会发布屏幕四边都是瀑布曲边的手机产品)
配置项 | 说明 |
---|---|
waterfall_display_left_edge_size | 瀑布屏左部边缘曲边弧长 |
waterfall_display_top_edge_size | 瀑布屏顶部边缘曲边弧长 |
waterfall_display_right_edge_size | 瀑布屏右部边缘曲边弧长 |
waterfall_display_bottom_edge_size | 瀑布屏底部边缘曲边弧长 |
瀑布屏API接口
Android 11对于瀑布屏手机,更新了专门的UI优化,以减少屏幕两端的曲面部分对显示画面或操作的影响。此次优化类似于之前Android系统适配刘海屏、挖孔屏的方案,Android通过一个DisplayCutout API来帮助应用识别屏幕上是否有空缺或挖孔,以此来避免元素或控件被遮挡,而这次安卓AAndroid 11 对DisplayCutout API进行了扩展,添加了一个DisplayCutout区域用以标记屏幕曲面部分。
应用可以使用现有的凹口屏 API 来管理挖孔屏幕和瀑布屏幕。还有新的 API 可以让您的应用使用包括边缘在内的整个瀑布屏幕,并通过边衬区 (insets) 来管理边缘附近的互动。使用新的API更新应用后,应用可以选择避开在此区域放置内容。
关键API
刘海屏/瀑布屏一些关键的API如下
【frameworks/base/core/java/android/view/WindowInsets.java】
class WindowInsets {
DisplayCutout getDisplayCutout();
}
【frameworks/base/core/java/android/view/DisplayCutout.java】
class DisplayCutout {
public int getSafeInsetLeft()
public int getSafeInsetTop()
public int getSafeInsetRight()
public int getSafeInsetBottom()
public Rect getSafeInsets()
public @NonNull Rect getBoundingRectLeft()
public @NonNull Rect getBoundingRectTop()
public @NonNull Rect getBoundingRectRight()
public @NonNull Rect getBoundingRectBottom()
public Rect[] getBoundingRectsAll()
public List<Rect> getBoundingRects()
public @NonNull Insets getWaterfallInsets()
}
API | 说明 |
---|---|
public int getSafeInsetLeft() | 返回安全区域距离屏幕左边的距离,单位是 px |
public int getSafeInsetTop() | 返回安全区域距离屏幕顶部的距离,单位是 px |
public int getSafeInsetRight() | 返回安全区域距离屏幕右边的距离,单位是 px |
public int getSafeInsetBottom() | 返回安全区域距离屏幕底部的距离,单位是 px |
public Rect getSafeInsets() | 返回 Rects 的列表,每个 Rects 都是屏幕上非功能区域的边界矩形。 |
public @NonNull Rect getBoundingRectLeft() | 返回位于屏幕左侧边缘非功能区域的矩形边框。 |
public @NonNull Rect getBoundingRectTop() | 返回位于屏幕顶部边缘非功能区域的矩形边框。 |
public @NonNull Rect getBoundingRectRight() | 返回位于屏幕右侧边缘非功能区域的矩形边框。 |
public @NonNull Rect getBoundingRectBottom() | 返回位于屏幕底部边缘非功能区域的矩形边框。 |
public Rect[] getBoundingRectsAll() | 返回一个矩形数组,每个子项是各个边缘非功能区域的矩形边框 |
public List
|
返回一个矩形列表,每个矩形是显示的非功能区域的边界矩形。 |
public @NonNull Insets getWaterfallInsets | 返回代表瀑布屏弧形区域的边衬区(Insets),Android 11新增API,专门针对瀑布屏设备类型。 |
【frameworks/base/graphics/java/android/graphics/Insets.java】
class Insets {
private Insets(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
}
layoutInDisplayCutoutMode 窗口属性
针对刘海屏(包括瀑布屏),Android 11 提供了4种窗口布局属性 layoutInDisplayCutoutMode,以提供给应用为设备屏幕缺口周围的内容进行布局。应用可以根据需求将此窗口属性设为下列值之一:
窗口属性 |
---|
LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT |
LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES |
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER |
LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS |
各个属性值说明如下:
(1) LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
默认情况下,全屏窗口不会使用到刘海区域,非全屏窗口可正常使用刘海区域。仅仅当系统提供的 bar 完全包含了缺口区时才允许 window 延伸到缺口区,否则 window 不会和屏幕缺口区重叠。
//在实际使用中,这意味着如果窗口没有设置以下几种属性:
- FLAG_FULLSCREEN
- View.SYSTEM_UI_FLAG_FULLSCREEN
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION),
如果缺口在屏幕顶部(或底部),它可以延伸到竖屏的缺口区域。否则(即全屏或横屏)它不会和缺口区域重叠。 也就是说此模式在全屏下不允许使用缺口区域。
(2) LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
窗口声明使用刘海区域,允许 window 延伸到短边的缺口区。
(3) LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
窗口声明不使用刘海区域,不允许 window 延伸到缺口区。
(4) LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
窗口总是允许扩展到屏幕所有边缘的缺口区。
官方相关技术文档
如需详细了解瀑布屏相关官方技术文档,请参阅以下官方链接:
WindowInsets.getDisplayCutout()
android:windowLayoutInDisplayCutoutMode
瀑布屏应用适配
调试
- 瀑布屏真机调试
- 模拟器模拟(Android 11以上)
设置–系统–开发者选项–刘海屏–瀑布刘海屏,可以看到设置完,整个系统页面都进行了更新, 屏幕两端进行了一定边距的留白,由此模拟瀑布屏的左右曲边弧长。
应用适配瀑布屏
瀑布屏手机屏幕边缘有弧形区域,一般来讲,非必要情况下这些区域不应该显示内容或响应应用操作。如果应用程序必须在该区域显示UI或处理那些insets中的触摸输入,需要格外小心,因为弧形区域可能会影响清晰度,并经常导致意外的触摸输入。
要确定这些屏幕缺口区域是否存在及其位置,可以使用 getDisplayCutout()函数获取DisplayCutout实例。利用DisplayCutout提供的相关API对应用进行适配。
如需在瀑布区域中呈现应用内容,可执行以下操作:
- 调用 DisplayCutout.getWaterfallInsets() 以获取瀑布边衬区的精确尺寸
- 将窗口布局属性 layoutInDisplayCutoutMode 设为 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS,以允许窗口延伸到屏幕各个边缘上的刘海和瀑布区域。您必须确保刘海或瀑布区域中没有重要的内容。
注意:如果未将上述窗口布局属性设为 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS,Android 会在黑边模式下显示窗口,从而避开缺口和瀑布区域。
瀑布屏获取相关参数举例:
DisplayCutout mDisplayCutout = getRootWindowInsets().getDisplayCutout();
Insets mInsets = mDisplayCutout.getWaterfallInsets();
int left = mInsets.left;
int right = mInsets.right;
设置窗口属性举例:
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.layoutInDisplayCutoutMode
= WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
getWindow().setAttributes(lp);
参考资料
https://developer.android.com/reference/android/view/DisplayCutout
https://developer.android.google.cn/reference/android/view/DisplayCutout.html
https://developer.android.com/preview/features
https://source.android.com/devices/tech/display/display-cutouts
修改说明
作者 | 版本 | 修改时间 | 修改说明 |
---|---|---|---|
WalkAloner | V1.0 | 2020/11/11 | 首版 |
本文地址:https://blog.csdn.net/luzhenrong45/article/details/109631820