Android 11----瀑布屏初识

本文介绍了Android11对瀑布屏的支持,包括系统配置方法、API接口和应用适配技巧。详细解释了如何通过配置文件模拟瀑布屏效果,以及如何利用DisplayCutout API避免应用内容被屏幕边缘遮挡。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android 11----瀑布屏初识

声明

博客地址:http://blog.csdn.net/luzhenrong45


瀑布屏简介

最近开始适配Android R,因此需要对Android R上的一些新特性功能进行大致了解,其中就有包括Google对瀑布屏的原生支持。瀑布屏手机是指拥有超高曲率的曲面屏手机,一种无边框的全面屏,被视为刘海屏的变体。目前国内华米OV都推出了自家的瀑布屏手机产品,比如华为Mate 40 Pro、vivo NEX 3、小米10等,瀑布屏可以说是2020下半年旗舰手机的标配特性之一了。

waterfall_cutout_phones


瀑布屏系统配置

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 getBoundingRects() 返回一个矩形列表,每个矩形是显示的非功能区域的边界矩形。
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;
    }
}

–> DisplayCutout API官方文档

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

窗口总是允许扩展到屏幕所有边缘的缺口区。

官方相关技术文档

如需详细了解瀑布屏相关官方技术文档,请参阅以下官方链接:

DisplayCutout

WindowInsets

WindowInsets.getDisplayCutout()

layoutInDisplayCutoutMode

android:windowLayoutInDisplayCutoutMode

瀑布屏应用适配

调试

  • 瀑布屏真机调试
  • 模拟器模拟(Android 11以上)

    设置–系统–开发者选项–刘海屏–瀑布刘海屏,可以看到设置完,整个系统页面都进行了更新, 屏幕两端进行了一定边距的留白,由此模拟瀑布屏的左右曲边弧长。

1_meitu_1_gaitubao_1613x1183

应用适配瀑布屏

瀑布屏手机屏幕边缘有弧形区域,一般来讲,非必要情况下这些区域不应该显示内容或响应应用操作。如果应用程序必须在该区域显示UI或处理那些insets中的触摸输入,需要格外小心,因为弧形区域可能会影响清晰度,并经常导致意外的触摸输入。

要确定这些屏幕缺口区域是否存在及其位置,可以使用 getDisplayCutout()函数获取DisplayCutout实例。利用DisplayCutout提供的相关API对应用进行适配。

如需在瀑布区域中呈现应用内容,可执行以下操作:

注意:如果未将上述窗口布局属性设为 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

《三星钻孔屏适配指导》


修改说明

作者版本修改时间修改说明
WalkAlonerV1.02020/11/11首版
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值