如何使用 WindowInsets 启用和禁用全屏模式?
How to enable and disable full screen mode using WindowInsets?
我有 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
回答
因此我们可以更轻松地使用扩展函数,因为我们还需要遗留代码。
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
}
}
就是这样。对我来说,它既适用于遗留代码,也适用于新代码。谢谢。
我有 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
回答
因此我们可以更轻松地使用扩展函数,因为我们还需要遗留代码。
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
}
}
就是这样。对我来说,它既适用于遗留代码,也适用于新代码。谢谢。