如何从SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION中恢复?

时间:2015-09-04 09:04:50

标签: android android-layout android-actionbar-compat android-actionbaractivity

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

我们想在"正常"之间来回切换。和"全屏"布局,我E:

  • 一个布局,其中内容仅占用导航栏和状态栏内留下的空间
  • 一个布局,其中内容占据整个屏幕并在导航和状态栏下滑动

要从普通模式切换到全屏模式,我们正在使用:

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);

所以,从这个

Layout after app start

我们首先"扩展"对此:

Layout after "expand" click

但是"萎缩"回不起作用:

Layout after "expand" and "shrink"

所以,似乎虽然Activity只允许在系统UI内部绘制,但它仍然会认为"它应该为系统UI留出空间。

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

我们使用的AppCompatActivity主题为Theme.AppCompat.Light.DarkActionBar

1 个答案:

答案 0 :(得分:3)

似乎布局的根目录为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,它将通知系统它必须再次应用insets:

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

现在,您可以调用setFit(false)在系统用户界面和setFit(true)后面制作视图布局,以使布局适合系统窗口。

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