如何从 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 恢复?

How to recover from SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION?

这个问题实际上出现在更复杂的情况下,涉及方向变化和纵向和横向的不同布局,但在它的最小版本中,问题是这样的:

我们想在 "normal" 和 "fullscreen" 布局之间来回切换,即。即:

要从普通屏幕切换到全屏,我们使用:

public static final int EXPAND_FLAGS = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;

getWindow().getDecorView().setSystemUiVisibility(EXPAND_FLAGS);

为了切换回来,我们尝试了:

public static final int SHRINK_FLAGS = View.SYSTEM_UI_FLAG_VISIBLE;

getWindow().getDecorView().setSystemUiVisibility(SHRINK_FLAGS);

所以,从这个

我们先"expand"到这个:

但 "shrinking" 返回不起作用:

所以,似乎 Activity 只允许在系统内部绘制 UI 它仍然 "thinks" 它应该为系统 space =59=].

所以我的问题是:SHRINK_FLAGS 在我上面的代码中应该是什么,或者我应该做什么完全不同的事情?

我们正在使用带有 Theme.AppCompat.Light.DarkActionBar 主题的 AppCompatActivity

您布局的根目录似乎有 android:fitsSystemWindows="true"。由于某些我不知道的原因,fitsSystemWindows 在更改系统 UI 标志时效果不佳。幸运的是,这个问题有一个解决方法。

首先,无条件设置扩展系统UI标志:

getWindow().getDecorView().setSystemUiVisibility(
        View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
);

然后从布局的所有祖先视图中删除 android:fitsSystemWindows="true"

之后,创建一个布局来处理系统插入更改,并根据其 属性 的值添加或删除填充。这是最复杂的部分。您必须根据平台版本以不同方式处理系统插入。对于 20 以下的版本(Kitkat Watch),您必须重写 View.fitSystemWindows() 方法:

@Override
protected boolean fitSystemWindows(final Rect insets) {
    if (mFit) {
        setPadding(insets.left, insets.top, insets.right, insets.bottom);
        // Do not propagate the system insets further.
        return true;
    } else {
        setPadding(0, 0, 0, 0);
        // Do not consume the insets and allow other views handle them.
        return false;
    }
}

平台版本大于或等于20需要重写View.onApplyWindowInsets()方法,和之前的方法一样处理:

@Override
public WindowInsets onApplyWindowInsets(final WindowInsets insets) {
    if (mFit) {
        setPadding(
                insets.getSystemWindowInsetLeft(),
                insets.getSystemWindowInsetTop(),
                insets.getSystemWindowInsetRight(),
                insets.getSystemWindowInsetBottom()
        );
        return insets.consumeSystemWindowInsets();
    } else {
        setPadding(0, 0, 0, 0);
        return insets;
    }
}

最后为 mFit 字段创建一个 setter,它将通知系统它必须再次应用插入:

mFit = fit;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
    requestApplyInsets();
} else {
    requestFitSystemWindows();
}

现在您可以调用 setFit(false) 使您的视图布局落后于系统 UI 和 setFit(true) 使布局适合系统 windows.

您可以获得此布局的源代码here