状态栏是顶部的电池电量、信号等显示的栏目。导航栏是底部的虚拟控制键栏目。
使用FLAG_LOW_PROFILE标志
// 使用decorView或者其他任何可见的View
View decorView = getActivity().getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_LOW_PROFILE;
decorView.setSystemUiVisibility(uiOptions);
设置后点击状态栏和导航栏即可使其恢复正常状态,并且清除这个标志。
4.0及以下的隐藏方式有两种,使用WindowManager隐藏或者在xml中设置。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT < 16) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
setContentView(R.layout.activity_main);
}
...
}
可以同时添加 FLAG_LAYOUT_IN_SCREEN标志,避免因为状态栏的显示和隐藏导致布局跳变。
...
xml设置比较容易维护不出错,而且在activity渲染之前就确定了状态栏隐藏,过渡比较流畅。
View decorView = getWindow().getDecorView();
// Hide the status bar.
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
ActionBar actionBar = getActionBar();
actionBar.hide(); // 隐藏状态栏的时候actionBar也应该隐藏起来
注意点:
- 如果标志清空了(比如离开了设置了标志的界面),就需要重新设置标志。
- 如果在onCreate()中设置全屏,点击Home键跳转出去,则状态栏会重新出现,再返回该界面时,由于onCreate()不会再次执行,所以状态栏保持可见,所以如果需要跳转回来仍不可见,则需要在onResume()或者onWindowFocusChanged()中设置标志。
- setSystemUiVisibility()只在调用该方法的View可见的情况下才生效,然后所有在view上设置的这些标志都会汇总到window级别改变系统ui。
- 跳转离开设置了标志的view后其设置的标志会被清除。
4.1开始可以使用 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN使布局充满原先状态栏所在位置,就不会因为状态栏的隐藏出现产生跳变。同时需要设置SYSTEM_UI_FLAG_LAYOUT_STABLE标志使布局稳定。
使用这种方式时,需要注意不要让布局被状态栏遮盖住,可以使用android:fitsSystemWindows属性,这会让父布局为系统状态栏留出padding空间。如果想要修改这个padding,可以调用 fitSystemWindows(Rect insets)方法来实现。
5.0(API21)开始可以通过设置Activity主题的两个属性实现透明状态栏或其他颜色。以下为继承应用主题的自定义主题。windowDrawsSystemBarBackgrounds为true是statusBarColor属性生效的条件。
设置了以上代码之后还需要在xml中显示到状态栏区域的View及其各层父布局中都设置fitSystemWindow为true才能正常显示。
View decorView = getWindow().getDecorView();
// 导航栏和状态栏最好同时隐藏
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
注意点:
- 点击屏幕任意地方会清除标志,重新显示状态栏和导航栏。
- 设置时机很关键,onCreate()中设置和onResume()或者onWindowFocusChanged()是不一样的。
- 调用 setSystemUiVisibility()的View如果不可见则该方法不生效。
- 从设置标志的View跳转离开的话标志就会被清除。
- 设置内容显示在导航栏所在位置,与状态栏做法一致。
沉浸式模式与普通全屏模式的区别就是全屏模式点击屏幕就会退出全屏,沉浸式模式在顶部下拉时才会退出全屏,粘性沉浸式在顶部下拉时短暂出现透明状态栏后自动消失。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
uiOptions ^= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
uiOptions ^= View.SYSTEM_UI_FLAG_FULLSCREEN;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
uiOptions ^= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
}
getWindow().getDecorView().setSystemUiVisibility(uiOptions);
int uiOptions = getWindow().getDecorView().getSystemUiVisibility();
// 检测当前是否沉浸式
boolean isImmersiveModeEnabled =
((uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) == uiOptions);
清空标志:
getWindow().getDecorView().setSystemUiVisibility(0);
沉浸式体验应该设置三个标志FULL_SCREEN、HIDE_NAVIGATION和IMMERSIVE或者IMMERSIVE_STICKY,并且清除掉LOW_PROFILE标志
int uiOptions = flagsView.getSystemUiVisibility();
uiOptions &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; // 清除标志
uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN; // 添加标志
uiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
uiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE;
uiOptions &= ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
int uiOptions = flagsView.getSystemUiVisibility();
uiOptions &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN;
uiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
uiOptions &= ~View.SYSTEM_UI_FLAG_IMMERSIVE;
uiOptions &= ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
flagsView.setSystemUiVisibility(uiOptions);
使用以下代码设置使布局出现在状态栏下方,所以沉浸式切换不会因为状态栏消失导致跳变,但是状态栏显示后会覆盖住布局内容:
int uiOptions = flagsView.getSystemUiVisibility();
uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
flagsView.setSystemUiVisibility(uiOptions);
可以封装成下面的方法
// This snippet hides the system bars.
private void hideSystemUI() {
// Set the IMMERSIVE flag.
// Set the content to appear under the system bars so that the content
// doesn't resize when the system bars hide and show.
mDecorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
| View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
| View.SYSTEM_UI_FLAG_IMMERSIVE);
}
// This snippet shows the system bars. It does this by removing all the flags
// except for the ones that make the content appear under the system bars.
private void showSystemUI() {
mDecorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
可以通过Handler.postDelay设置IMMERSIVE标志自行实现粘性沉浸式。
可以通过设置GestureDetector的onSingleTapUp(MotiveEvent)切换IMMERSIVE标志。
View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
(new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
// Note that system bars will only be "visible" if none of the
// LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
// 状态栏可见
} else {
// 状态栏不可见
}
}
});