不推荐使用android.view.View.systemUiVisibility。什么是替代品?

时间:2020-06-25 14:24:41

标签: android kotlin

我已经将项目目标API版本更新为30,现在我发现不赞成使用systemUiVisibility属性。

下面的kotlin代码是我正在使用的代码,它实际上等效于Java中的setSystemUiVisibility方法。

playerView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE
            or View.SYSTEM_UI_FLAG_FULLSCREEN
            or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)

如果您已对该不推荐使用的代码进行任何稳定的替换,请告诉我。谷歌的建议是使用WindowInsetsController,但我不建议这样做。

9 个答案:

答案 0 :(得分:14)

希望它能对您有所帮助。

以前,在实施边缘到边缘导航或沉浸式模式时,要采取的第一步措施是使用systemUiVisibility标志,以要求将应用全屏显示, 这个新的Android版本不赞成使用此字段,并且要全屏布局应用,您必须在Window类上使用新方法:setDecorFitsSystemWindows传递false作为如下参数。

window.setDecorFitsSystemWindows(false)

WindowInsetsController类,它允许您执行以前通过systemUiVisibility标志进行控制的操作,例如隐藏或显示状态栏或导航栏(分别为隐藏和显示方法)

例如,您可以轻松显示和隐藏键盘,如下所示:

// You have to wait for the view to be attached to the
// window (otherwise, windowInsetController will be null)
view.doOnLayout {
    view.windowInsetsController?.show(WindowInsets.Type.ime())
    // You can also access it from Window
    window.insetsController?.show(WindowInsets.Type.ime())
}

答案 1 :(得分:9)

1.5.0-alpha02版开始,androidx.core的{​​{1}}

启用边缘到边缘:

WindowCompat.setDecorFitsSystemWindows()

答案 2 :(得分:9)

TL; DR代码段

需要使用if-else结构进行包装,以避免在旧版SDK上出现java.lang.NoSuchMethodError: No virtual method setDecorFitsSystemWindows异常。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    window.setDecorFitsSystemWindows(false)
} else {
    window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
}

链接,其中包含有关Android 11中的插图和全屏模式的完整信息

https://blog.stylingandroid.com/android11-windowinsets-part1/

https://www.youtube.com/watch?v=acC7SR1EXsI

答案 3 :(得分:3)

由于您可能希望将minSdkVersion设置为小于30,因此建议您使用WindowCompatWindowInsetsControllerCompat。您需要将androidx.core的gradle依赖关系至少升级到1.5.0-alpha02

通过观看YouTube video

,您可以找到有关WindowInsets的更多信息
private fun hideSystemUI() {
    WindowCompat.setDecorFitsSystemWindows(window, false)
    WindowInsetsControllerCompat(window, mainContainer).let { controller ->
        controller.hide(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars())
        controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
    }
}

private fun showSystemUI() {
    WindowCompat.setDecorFitsSystemWindows(window, true)
    WindowInsetsControllerCompat(window, mainContainer).show(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars())
}

编辑:

我发现使用此Alpha库在某些设备上设置systemBarsBehavior可能存在问题。请在Google的问题跟踪网站上查看bug report。 *星虫报告,以引起更多关注

在修复该错误之前,我建议使用以下替代方法:

private fun hideSystemUI() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        window.setDecorFitsSystemWindows(false)
        window.insetsController?.let {
            it.hide(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars())
            it.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
        }
    } else {
        @Suppress("DEPRECATION")
        window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_FULLSCREEN
                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)
    }
}

答案 4 :(得分:2)

如果有人搜索 Java 版本。

对于Activity

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    getWindow().setDecorFitsSystemWindows(false);

    if (getWindow().getInsetsController() != null) {
        getWindow().getInsetsController().hide(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars());
        getWindow().getInsetsController().setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
    }
} else {
    getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}

对于 FragmentDialogAlertDialog

if (getDialog() != null && getDialog().getWindow() != null) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        getDialog().getWindow().setDecorFitsSystemWindows(false);
    } else {
        if (getActivity() != null) {
            getDialog().getWindow().getDecorView().setSystemUiVisibility(getActivity().getWindow().getDecorView().getSystemUiVisibility());
        }
    }
}

答案 5 :(得分:0)

答案 6 :(得分:0)

此外,您可能希望拥有一个半透明的状态栏,并且只需通过为应用程序的主题设置样式即可,如下所示:

<style name="App.MyTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <item name="android:windowLightStatusBar">true</item>
</style>

可能会显示一条皮棉条消息(取决于您当前的最低API级别): android:windowLightStatusBar需要API级别23(当前最小值为21),因此您需要在v23样式中覆盖此主题

答案 7 :(得分:0)

根据Chris Banes @ Android Developers official youtube channel 使用以下代码

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var view: View

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        view = binding.root
        setContentView(view)
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if (hasFocus) hideSystemUI()
    }

    private fun hideSystemUI() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
             // Tell the window that we want to handle/fit any system windows
             WindowCompat.setDecorFitsSystemWindows(window, false)

             val controller = view.windowInsetsController

             // Hide the keyboard (IME)
             controller?.hide(WindowInsets.Type.ime())

             // Sticky Immersive is now ...
             controller?.systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

             // When we want to hide the system bars
             controller?.hide(WindowInsets.Type.systemBars())

             /*val flag = WindowInsets.Type.statusBars()
             WindowInsets.Type.navigationBars()
             WindowInsets.Type.captionBar()
             window?.insetsController?.hide(flag)*/
        } else {
            //noinspection
            @Suppress("DEPRECATION")
            // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
            window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                // 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)
        }
    }
}

这是示例链接 User interface sample

答案 8 :(得分:0)

对于 Java 用户(感谢@James):

//hide system UI
Window window = activity.getWindow();
View decorView = activity.getWindow().getDecorView();

WindowCompat.setDecorFitsSystemWindows(window, false);
WindowInsetsControllerCompat controllerCompat = new WindowInsetsControllerCompat(window, decorView);
controllerCompat.hide(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.navigationBars());
controllerCompat.setSystemBarsBehavior(WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE);
相关问题