如何从 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 恢复?
How to recover from SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION?
这个问题实际上出现在更复杂的情况下,涉及方向变化和纵向和横向的不同布局,但在它的最小版本中,问题是这样的:
我们想在 "normal" 和 "fullscreen" 布局之间来回切换,即。即:
- 一种布局,其中内容仅占据导航栏和状态栏内部的 space
- 内容占据整个屏幕并在导航栏和状态栏下方滑动的布局
要从普通屏幕切换到全屏,我们使用:
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。
这个问题实际上出现在更复杂的情况下,涉及方向变化和纵向和横向的不同布局,但在它的最小版本中,问题是这样的:
我们想在 "normal" 和 "fullscreen" 布局之间来回切换,即。即:
- 一种布局,其中内容仅占据导航栏和状态栏内部的 space
- 内容占据整个屏幕并在导航栏和状态栏下方滑动的布局
要从普通屏幕切换到全屏,我们使用:
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。