【问题标题】:How to enable and disable full screen mode using WindowInsets?如何使用 WindowInsets 启用和禁用全屏模式?
【发布时间】:2021-07-20 08:59:01
【问题描述】:

我有 2 个功能,可帮助我在我的应用中启用和禁用全屏模式。默认情况下,我的应用程序未处于全屏模式。我想要的行为是当用户打开一个片段时,5 秒后我启用全屏模式。当用户触摸屏幕时,我禁用全屏模式,但 3 秒后我再次启用它。 这是我编写的代码(我使用的是旧版本)

private fun enableFullScreen() {
    fullScreenModeEnabled = true
    // From docs
    decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
            or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            or View.SYSTEM_UI_FLAG_FULLSCREEN)
}

private fun disableFullScreen() {
    if (fullScreenModeEnabled) {
        // From docs
        decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)

        fullScreenModeEnabled = false
    }

    handler.removeCallbacks(enableFullScreenRunnable)
    handler.postDelayed(enableFullScreenRunnable, 3000)
}

enableFullScreenRunnable 是一个简单的可运行对象,它在一定延迟后调用enableFullScreen() 函数。当用户打开片段时,5 秒后我使用处理程序和可运行对象调用 enableFullScreen() 函数。我有一个根视图的点击监听器,所以当用户点击屏幕时,我调用disableFullScreen()

rootView.setOnClickListener {
        disableFullScreen()
}

最后,我有一些 UI 元素,例如一个 textView,需要与我的应用程序的状态同步。因此,当应用程序进入全屏模式时,我必须隐藏我的 textView,反之亦然。

 decorView.setOnSystemUiVisibilityChangeListener { visibility ->
        if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
            textView.visibility = View.VISIBLE
        } else {
            textView.visibility = View.INVISIBLE
        }
 }

问题是,Android 11 不推荐使用所有这些标志。在 Android Studio 中,它说使用 WindowsInsets 而不是这些标志。如何使用 WindowInsets 实现相同的功能?在官方文档中,代码不是最新的,仍然使用旧标志here

【问题讨论】:

    标签: android kotlin android-fullscreen windowinsets


    【解决方案1】:

    回答

    所以我们可以更轻松地使用扩展函数,因为我们还需要遗留代码。

    fun Activity.enableFullScreen() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.insetsController?.let {
                it.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
                it.hide(WindowInsets.Type.systemBars())
            }
        } else {
            @Suppress("DEPRECATION")
            window.decorView.systemUiVisibility = (
                 View.SYSTEM_UI_FLAG_IMMERSIVE
                     // Set the content to appear under the system bars so that the
                     // content doesn't resize when the system bars hide and show.
                     or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                     or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                     or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                     // Hide the nav bar and status bar
                     or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                     or View.SYSTEM_UI_FLAG_FULLSCREEN
                )
        }
    }
    
    fun Activity.disableFullScreen() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.setDecorFitsSystemWindows(false)
            window.insetsController?.show(WindowInsets.Type.systemBars())
        } else {
            @Suppress("DEPRECATION")
            window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
        }
    }
    

    所以在我的片段中我只有一个功能。

    private fun disableFullScreen() {
        if (fullScreenModeEnabled) {
            requireActivity().disableFullScreen()
        }
    
        handler.removeCallbacks(enableFullScreenRunnable)
        handler.postDelayed(enableFullScreenRunnable, 5000)
    }
    

    当用户点击屏幕时,我会像这样禁用全屏。

    rootView.setOnClickListener {
        disableFullScreen()
    }
    

    唯一剩下的就是听者了。所以我们也为它创建了一个这样的扩展函数。

    fun Window.addSystemUIVisibilityListener(visibilityListener: (Boolean) -> Unit) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            decorView.setOnApplyWindowInsetsListener { v, insets ->
                val suppliedInsets = v.onApplyWindowInsets(insets)
                // only check for statusBars() and navigationBars(), because captionBar() is not always
                // available and isVisible() could return false, although showSystemUI() had been called:
                visibilityListener(suppliedInsets.isVisible(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars()))
                suppliedInsets
            }
        } else {
            @Suppress("DEPRECATION")
            decorView.setOnSystemUiVisibilityChangeListener {
                visibilityListener((it and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0)
            }
        }
    }
    

    在我们的片段中,我们像这样使用它。

    requireActivity().window.addSystemUIVisibilityListener { isVisible ->
        if (isVisible) {
            textView.visibility = View.VISIBLE
            fullScreenModeEnabled = false
        } else {
            textView.visibility = View.INVISIBLE
            fullScreenModeEnabled = true
        }
    }
    

    就是这样。对我来说,它适用于旧代码和新代码。谢谢。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-23
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多