AndroidWin11安卓

Android 实现沉浸式全屏的总结

2022-09-08  本文已影响0人  super可乐

前言

本文总结 Android 实现沉浸式全屏的实现方式。

实现沉浸式全屏

在一些需要全屏显示的场景下,比如玩游戏、看横屏视频的时候,内容全屏占满窗口的体验会让用户更加沉浸到对内容的消费中,带来更好的用户体验。

沉浸式显示具体来说就是如状态栏和导航栏部分的显示效果调整。当然,这里对于不同的产品形态会有不同的选择。

状态栏文本、icon 的颜色、状态栏本身的背景色、导航栏的背景色以及是否显示,通过这些组合可以呈现出不同的用户体验。下面就从这两个组件的使用出发,看看如何实现沉浸式的效果。

状态栏

状态栏背景色

关于状态栏,首先是状态栏背景色, 这个根据需要设置就好了,一般情况下设置为透明比较好适配。

window.statusBarColor = Color.TRANSPARENT

状态栏文字颜色

关于状态栏、导航栏的其他操作,我们可以使用系统的 WindowInsetsControllerCompat 这个类,从名字 Compat 就可以看到,这是一个兼容的类。关于沉浸式状态栏的实现,由于 Android 在国内变成了「安卓」,因此早期关于状态各种属性的适配可以说是群魔乱舞,各式各样的 StatusBarUtils 大行其道。现在好了,Android 官方终于一统天下,亲自下场来搞了,这下关于沉浸式的实现就比较简单了。

WindowInsetsControllerCompat 的使用也很简单,创建一个他的实例即可。

val controller = WindowInsetsControllerCompat(window, window.decorView)

后面的一切使用这个实例就可以了,API 很简单,命名一目了然。

比如更改状态颜色这个功能。关于状态栏文字的颜色,Android 官方只允许设置黑色或者白色

controller.isAppearanceLightStatusBars = true // 黑色状态栏

// or 

controller.isAppearanceLightStatusBars = false // 白色状态栏

注意、注意、注意 ,这里的注释没有写错,这个方法就是这么奇怪,自己一开始使用也是被绕晕了。但就是这样。还有一点需要注意的是,Android 6.0 也就是 Android SDK 23 开始,才可以使用这个 feature 。

状态栏显示与隐藏

controller.hide(WindowInsetsCompat.Type.statusBars()) // 状态栏隐藏

// or

controller.show(WindowInsetsCompat.Type.statusBars()) // 状态栏显示

这个就很简单了。

导航栏

说完了状态栏,在来看导航栏。相比状态栏,导航栏上不会有文字,一般情况下就是一条底部的横线。因此,我们只需要关心导航的背景色和可见性即可。

导航栏背景色

window.navigationBarColor = Color.TRANSPARENT

导航栏横线的颜色

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    window.navigationBarDividerColor = Color.TRANSPARENT
}

从 Android P (28) 也就是 Android 9.0 开始,我们甚至可以设置导航栏横线的颜色了。

导航栏显示与隐藏

导航栏显示与隐藏的方法,和状态栏显示隐藏的方法非常相似,改变一下参数即可。

controller.hide(WindowInsetsCompat.Type.navigationBars()) // 导航栏隐藏

// or

controller.show(WindowInsetsCompat.Type.navigationBars()) // 导航栏显示

沉浸式

WindowCompat.setDecorFitsSystemWindows(window, false) // 打开沉浸式
// or
WindowCompat.setDecorFitsSystemWindows(window, true) // 关闭沉浸式
沉浸式开 沉浸式关闭

可以看到,使用 WindowInsetsControllerCompat ,沉浸式就是这么简单。

适配全面屏

从上面沉浸式的图,可以看到其实还是有点问题,就是横屏之后,屏幕左边并没有完全铺开,而是有一段黑边,看着非常难受了。这其实是关于异形屏的适配问题。

其实这段黑边就是刘海屏的区域,Android 官方叫做 DisplayCutout area 这个区域也是有专门的参数进行适配。

val params = window.attributes
params.layoutInDisplayCutoutMode =
                        WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
window.attributes = params

大于等于 Android 9.0 (SDK 28 P)的设备都支持。关于 layoutInDisplayCutoutMode 参数有三种类型。

关于这三个参数,还要考虑当前屏幕是横屏还是竖屏。

LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT

这个是默认参数。

竖屏状态

如果没有设置全屏显示的属性,那么内容是延伸到 DisplayCutout area 的。这种情况下,如果进行全屏和非全屏的切换操作,会发现内容在整体上下跳动。比如在这种情况下,调用 controller.hide(WindowInsetsCompat.Type.statusBars()) 进行状态栏的显示隐藏的操作,就会发现整个内容在上下跳动,在上面的动图里很明显了。

横屏状态

横屏状态下,顶部的状态栏就变成左边或者右边(这里看屏幕是怎么旋转的,可能是旋转了 -90 度,也可能是 270 度)的黑边了。内容不会延伸到左右两边的 DisplayCutout area 里。

LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES

这种情况下,内容是默认延伸到 DisplayCutout area 的。因此,全屏和非全屏操作的时候,就不会有内容上下跳动或者黑边的问题了。

LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER

这种情况,内容永远不会延伸到 DisplayCutout area 里面。

关于这个三个参数和沉浸式状态的设置,可以进行自由组合,会有不同的效果。具体要怎样,就看实际业务需求了。 比如 Android 官方的相册应用,当我们点击一张图片进行预览的时候,顶部状态栏是全屏之后才慢慢隐藏的。

关于 LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 和 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 的区别,我们用两张图比较一下就大概明白了。

LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES

可以看到,LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 模式下,整个内容都撑开到刘海的区域了。屏占比更高了,看着也更舒服了。

需要注意的是,刘海屏适配还牵扯到屏幕内容高度(竖屏)或者内容宽度的计算问题。实际的分辨率、displayMetrics.widthPixelsdisplayMetrics.heightPixels 这些值是不变的。但是随着刘海区域的变化,实际内容可展示的区域是有变化的,因此还需要做好适配相关的问题。

总结

使用官方提供的 WindowInsetsControllerCompat 的系列 API,操作状态栏及导航栏,以及沉浸式的实现相对来说比较简单了,底层处理了各个版本之间的兼容性。关于文中提到的相关类和方法的使用,更多细节可以查看参考文档中的链接。

参考

作者:IAM四十二
链接:https://juejin.cn/post/7139495545206210590

上一篇下一篇

猜你喜欢

热点阅读