“沉浸式”体验?异形屏适配?我把他们扒光了明明白白告诉你应该这样作

看似复杂的沉浸式体验设计,其实也就是在处理如下两个 System UI与用户布局(setContentView)之间说不清理还乱的关系:java

  • StatusBar 系统状态栏
  • NavigationBar 系统导航栏

网上相似“沉浸式状态栏”的文章一搜一大把,且先不吐槽所谓的“沉浸式状态栏”说法正确与否,随便一篇文章都会告诉你,要实现沉浸式体验有两个关键地方:android

  • window.decorView.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or SYSTEM_UI_FLAG_LAYOUT_STABLE
  • window.statusBarColor = Color.TRANSPARENT

运行代码,果真实现了“沉浸式状态栏”的效果。但是我相信大多数人内心是迷糊的:微信

  • SYSTEM_UI_FLAG_LAYOUT_FULLSCREENSYSTEM_UI_FLAG_LAYOUT_STABLE 是什么?
  • 为何要设置状态栏颜色透明?设置其余颜色不能够么?

以及接下来可能碰到的各类“沉浸式状态栏”带来的坑:ide

  • Bull shit!用户布局 与 状态栏信息 重叠了
  • 可交互按钮被手机的“刘海”给挡住了
  • 状态栏上时间等信息的文字颜色是黑色,搭配上状态栏蓝色的背景,好丑啊

在讲解 沉浸式体验的实现异形屏 适配前,咱们须要先补下课,了解些微的基础知识:布局

各类Flag

STATUS_BAR_HIDDEN

/** * Android 3.0(API 11)加入 * * 已被废弃,现等同于 SYSTEM_UI_FLAG_LOW_PROFILE */
public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE;
复制代码

STATUS_BAR_VISIBLE

/** * Android 3.0(API 11)加入 * * 已被废弃,现等同于 SYSTEM_UI_FLAG_VISIBLE */
public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE;
复制代码

SYSTEM_UI_FLAG_VISIBLE

/** * Android 4.0(API 14)加入 * * 代表设置系统UI(status bar等)为可见状态, * 这也是默认效果。 */
public static final int SYSTEM_UI_FLAG_VISIBLE = 0;

复制代码

SYSTEM_UI_FLAG_LOW_PROFILE

/** * Android 4.0(API 14)加入 * * 低配模式,这里的低配不是传统意义上的低配置, * 我更倾向于称其为低调模式,设置系统UI进入不显眼的“低配置”模式。 * 具体表现为:状态栏 和/或 导航栏某些图标 可能变暗 */
public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001;

复制代码

SYSTEM_UI_FLAG_HIDE_NAVIGATION

/** * Android 4.0(API 14)加入 * * 若是设置了 SYSTEM_UI_FLAG_LOW_PROFILE 后仍是以为系统UI显眼, * 不妨尝试设置该Flag请求系统导航栏暂时隐藏, * 这将致使基本的导航控件(对于国内用户来讲就是Android的三大金刚键)消失 * 这对于充分使用设备屏幕极为有用,搭配 FLAG_LAYOUT_IN_SCREEN 食用效果更佳~ * * Tip:Google 认为导航控件十分重要,所以该Flag只会暂时性隐藏导航控件 * 用户的任何行为都会使导航栏控件从新出现,并 clear 掉该标志位 */
public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002;
复制代码

SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION

/** * Android 4.1(API 16)加入 * * 与 SYSTEM_UI_FLAG_HIDE_NAVIGATION 相比多了一个 LAYOUT 关键字, * 不一样的是,使用该 Flag 并不会隐藏 system UI, * 而是使用户的布局延伸至 system UI 下方, * 致使用户的布局被覆盖掉(可以使用fitSystemWindows(Rect)方法规避该问题) */
public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200;
复制代码

SYSTEM_UI_FLAG_FULLSCREEN

/** * Android 4.1(API 16)加入 * * 全屏模式,此模式用户的内容视图将覆盖整个屏幕, * 这就意味着非关键的屏幕装饰(例如状态栏,不包括导航栏,Google认为导航栏是很是重要的系统UI)将被隐藏 * 与 WindowManager.LayoutParams.FLAG_FULLSCREEN 不一样的是: * * 1.若是与 Window#FEATURE_ACTION_BAR_OVERLAY 一同使用,则 ActionBar 也会一同隐藏 * 2.该FLAG更易清除:与 系统UI交互(下拉显示通知) 或 跳转至其余应用 都会清除该FLAG */
public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004;
复制代码

SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

/** * Android 4.1(API 16)加入 * * 同 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 与 SYSTEM_UI_FLAG_HIDE_NAVIGATION 的区别同样, * 该 FLAG 与 SYSTEM_UI_FLAG_FULLSCREEN 区别就是该 FLAG 会使用户布局延伸至系统状态栏下方 * 致使用户的布局被系统状态栏覆盖掉(可以使用fitSystemWindows(Rect)方法规避该问题) */
public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400;
复制代码

SYSTEM_UI_FLAG_LAYOUT_STABLE

/** * Android 4.1(API 16)加入 * * 该标志位一般与其余FLAG一同使用,代表系统指望View的insets是固定不变的 * 这意味着即便当前 window 的 Flag 变化影响了系统UI的布局, * 用户界面的位置也并不会发生变化。 * * 单独使用该FLAG界面不会有任何变化。 */
public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100;
复制代码

SYSTEM_UI_FLAG_IMMERSIVE

/** * Android 4.4(API 19)加入 * * 该FLAG是用来修饰 SYSTEM_UI_FLAG_HIDE_NAVIGATION, * 若是咱们单独使用 SYSTEM_UI_FLAG_HIDE_NAVIGATION, * 那么用户与系统任何交互都会清除掉 SYSTEM_UI_FLAG_HIDE_NAVIGATION 这个FLAG * 搭配该FLAG后则不会清除掉,除非从屏幕顶部向下滑动。 */
public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800;
复制代码

SYSTEM_UI_FLAG_IMMERSIVE_STICKY

/** * Android 4.4(API 19)加入 * * 该FLAG与 SYSTEM_UI_FLAG_IMMERSIVE 不一样的是 * SYSTEM_UI_FLAG_IMMERSIVE 仅用来修饰 SYSTEM_UI_FLAG_HIDE_NAVIGATION, * SYSTEM_UI_FLAG_IMMERSIVE_STICKY 是用来修饰 SYSTEM_UI_FLAG_HIDE_NAVIGATION 与 * SYSTEM_UI_FLAG_FULLSCREEN 这两个Flag的。 * * 还有一点不一样的是,该FLAG在与系统UI交互后,会被短暂的clear, * 一下子自动恢复。 */
public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000;
复制代码

System UI 颜色

按照时间跨度来说,Android 系统的 System UI 经历了如下几个阶段:字体

Android 4.4,能够设置状态栏或者导航栏的背景为透明

从Android 4.4开始,Android 系统才开始了对 System UI 颜色的改造之路,固然,Android 4.4只是小试牛刀,只容许开发者设置状态栏或者导航栏背景透明,只须要在Application的Theme里加入如下代码:ui

<style name="AppTheme" parent="Theme.AppCompat"> <item name="android:windowTranslucentStatus">true</item> <item name="android:windowTranslucentNavigation">true</item> </style>
复制代码

该style在 Android 5.0 以上 和 如下的效果并不同:this

5.0如下表现为 一个渐变的半透明效果;spa

5.0以上取消了这个渐变效果。设计

Android 5.0,能够设置状态栏或者导航栏的颜色了

得益于 Google 在 Android 5.0 推出的 Material Design的设计语言,Android 开发者终于可以将状态栏和导航栏设置成任何你想要的颜色了,只需调用如下方法:

/** * Android 5.0(API 21)加入 * * 设置状态栏的颜色为 {@code color}。 * 值得注意的是,该方法与前面提到的“透明状态栏”是冲突的, * 这意味着,若是设置了“透明状态栏”, * 再调用该方法无效。 */
public abstract void setStatusBarColor(@ColorInt int color);

/** * Android 5.0(API 21)加入 * * 设置导航栏的颜色为 {@code color}。 * 值得注意的是,该方法与前面提到的“透明导航栏”是冲突的, * 这意味着,若是设置了“透明导航栏”, * 再调用该方法无效。 */
public abstract void setNavigationBarColor(@ColorInt int color);
复制代码

Android 6.0,能够设置状态栏中的图标、字体颜色了

Android 中系统状态栏中的字体、图标的颜色默认为浅色系(白色),若是App状态栏设计为浅色调的话,颇有可能致使用户看瞎了眼也看不清楚状态栏的各类信息。这个尴尬的点一直到Android 6.0以后才得以解决。

Android 6.0加入了更改状态栏内容颜色风格的Flag:

/** * Android 6.0(API 23)加入 * * 设置状态栏文字图标以“Light”模式绘制, * 通俗的讲,就是状态栏文字图标颜色变为黑色。 */
public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000;
复制代码

亦或者是经过在Style中进行以下设置来达到一样的效果:

<style name="AppTheme" parent="Theme.AppCompat"> <item name="android:windowLightStatusBar">true</item> </style>
复制代码

知道了上面这些,咱们能够作...

充分了解上面介绍的 Android 各类 SystemUI 的特性后,咱们就能够实现市面上大多数应用所谓的沉浸式体验了。下面咱们就来看几个🌰。

页面含有复杂背景/纹理

相似于QQ音乐歌曲播放详情页面这种含有复杂的背景以及纹理的页面,市面上常见的UI设计就是设置状态栏透明,同时使用户布局侵入状态栏下方

代码以下:

private fun translucent(){
        supportActionBar?.hide()
        val decorView =  window?.decorView
        decorView?.systemUiVisibility = 
  					View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 
  					or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
        window?.statusBarColor = Color.TRANSPARENT
    }
复制代码

效果以下:

用户布局顶部为纯色背景

而像支付宝这种用户布局顶部为纯色背景的设计,常见思路就是将statusbar的颜色设为同色且用户布局不侵占状态栏便可。

代码以下:

private fun translucent(){
        supportActionBar?.hide()
        window?.statusBarColor = Color.TRANSPARENT
    }
复制代码

设置完状态栏颜色后,不要忘记根据状态栏的颜色深浅设置状态栏图标对应的深色/浅色模式:
decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR状态栏浅色模式:对应的状态栏图标变为深色(黑色),不设置即为深色模式,对应的状态栏图标为浅色(白色)。

类电子书阅读器

相似于微信阅读这种,用户但愿在阅读电子书籍时可以全情投入不受系统状态栏信息变化的影响同时又可以随时呼出系统状态栏以及App的菜单。like this:

这种效果的实现很显然就是要动态更改 decorViewsystemUiVisibility了。若是你对上面介绍的各类 system ui flag了然于胸的话,必定可以不加思索的写出下面的代码:

/** * 根据传入的visible参数动态改变decorView的systemUiVisibility * * @param 是否展现 status bar */
    private fun changeSystemUI(visible: Boolean){
        var newVis = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
        llActionBar.visibility = View.VISIBLE
        if (!visible) {
            newVis =
                newVis or (ImageView.SYSTEM_UI_FLAG_LOW_PROFILE or ImageView.SYSTEM_UI_FLAG_FULLSCREEN
                        or ImageView.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
            llActionBar.visibility = View.GONE
        }
        val decorView = window?.decorView
        decorView?.systemUiVisibility = newVis
    }
复制代码

效果以下:

总结

这篇只是简单介绍了下Android View体系中的system ui的基础,关于Android P中的挖孔屏(notch)相关适配知识以及国内种类繁多的定制room系统(MIUI、EMOTION UI、Fly Me...)的system ui以及挖孔屏的适配,受制于篇幅,咱们放在下篇文章详细介绍。

总之,

路漫漫其修远兮,吾将上下而求索; 革命还没有成功,同志仍需努力!

相关文章
相关标签/搜索