Android 全屏显示和沉浸式显示

语言: CN / TW / HK

在App的开发中,为了提供更好的视觉效果,全屏显示和沉浸式显示都是很常见的。在我过去的开发经历中,通常使用ImmersionBar这个三方库来实现。今天介绍下一如何通过官方的API来实现。

沉浸式显示

沉浸式显示,是指还能看到状态栏,但是状态栏背景为透明的,与App的UI不会有明显的割裂感。

非沉浸式如图:

no_full_screen.png

实现沉浸式代码如下:

``` //修改全局主题中statusBarColor和navigationBarColor为透明

class ImmersionActivity : AppCompatActivity() {

private lateinit var windowInsetsController: WindowInsetsControllerCompat

lateinit var binding: LayoutImmersionActivityBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, R.layout.layout_immersion_activity)

    WindowCompat.setDecorFitsSystemWindows(window, false)
    windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
    windowInsetsController.isAppearanceLightNavigationBars = false

    binding.btnChangeToLightBar.setOnClickListener {
        //顶部布局为亮色
        lightBar()
    }

    binding.btnChangeToDarkBar.setOnClickListener {
        //顶部布局为深色
        darkBar()
    }
}

private fun lightBar() {
    binding.topView.setBackgroundColor(ContextCompat.getColor(this, R.color.white))
    binding.tvTitle.setTextColor(ContextCompat.getColor(this, R.color.black))
    setBarStatus(true)
}

private fun darkBar() {
    binding.topView.setBackgroundColor(ContextCompat.getColor(this, R.color.color_23242a))
    binding.tvTitle.setTextColor(ContextCompat.getColor(this, R.color.white))
    setBarStatus(false)
}

//改变状态栏文字和图标的颜色(根据顶部布局的背景色来决定)
private fun setBarStatus(light: Boolean) {
    windowInsetsController.isAppearanceLightStatusBars = light
}

}

```

效果如图:

1e9c7603289e48be8c4b52997b25e525_.gif

设置间距

可以看到,App顶部的标题与状态栏间距很小,与我想要的效果有所出入,底部的圆点控件也被透明的导航栏遮挡了。官方提供了相应的API来应对这些情况。

代码如下:

``` //重复的部分省略了 class ImmersionActivity : AppCompatActivity() { ... private var hadChange = false

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...

    ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
        //此回调会触发多次,所以用布尔值来控制仅触发一次
        if (!hadChange) {
            hadChange = true
            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
            //状态栏高度
            val statusBarHeight = insets.top
            //调整顶部控件的高度
            binding.topView.run {
                updateLayoutParams<ConstraintLayout.LayoutParams> {
                    height += statusBarHeight
                }
                updatePadding(top = paddingTop + statusBarHeight)
            }
            binding.tvTitle.run {
                updateLayoutParams<ConstraintLayout.LayoutParams> {
                    topMargin += statusBarHeight
                }
            }

            //导航栏高度
            val navigationBarHeight = insets.bottom
            //调整圆点控件不被导航栏遮挡
            binding.bottomView.run {
                updateLayoutParams<ConstraintLayout.LayoutParams> {
                    bottomMargin += navigationBarHeight
                }
            }
        }
        WindowInsetsCompat.CONSUMED
    }
    ...
}
...

}

```

效果如图:

Screenshot_20220716_111503.png

全屏显示

全屏显示,是指隐藏状态栏和导航栏,官方最新的API十分简单。

代码如下:

``` class FullScreenActivity : AppCompatActivity() {

lateinit var binding: LayoutFullScreenActivityBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, R.layout.layout_full_screen_activity)

    val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
    //控制系统栏的行为
    windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
    windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
}

} ```

注意:systemBarsBehavior用于控制用户的行为对系统栏的改变,有三种,分别为:

  • WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH
  • WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE
  • WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

BEHAVIOR_SHOW_BARS_BY_TOUCH和BEHAVIOR_SHOW_BARS_BY_SWIPE均表现为触摸或者滑动导致系统栏出现后不会自动隐藏,效果如下图:

22c78146cb8ec9e453add4b805029574_.gif

BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE表现为触摸或者滑动导致系统栏出现后,会在短时间内自动隐藏,效果如下图:

3275d5d9ae9de444422a627b9451995a_.gif