Android 沉浸式状态栏的实现
沉浸式到底是一种什么感觉呢?
用户完全沉浸的体验,使用户有一种置身于虚拟世界之中的感觉。
我真的很难理解这是一种什么感觉。。。。
直到读了一下郭霖大神的Android状态栏微技巧,带你真正理解沉浸式模式,才有了一点点感觉啊(所以这篇文章是在郭霖博客上加了一些东西,为了让自己的知识更加巩固)。对,就是玩游戏的时候,我们都想置身于那种玩游戏的快感,突然来个系统状态栏的话,我觉着我反正是受不了的,都想砸手机的感觉。
总之,重要的事情说三遍
Android沉浸式模式的本质就是全屏化
Android沉浸式模式的本质就是全屏化
Android沉浸式模式的本质就是全屏化
下面,看一下,手机界面的系统元素有哪些
手机界面元素而沉浸式模式就是要将这三个隐藏,我们需要注意的是,在android4.4之前,我们是没有办法设置状态栏的,4.4(API19)之后才会有这种沉浸式。
实现
1、通过设置Theme主题来设置状态栏和导航栏的透明度
这里,我们需要注意
Android5.0(API21)以上的状态栏,会有一层变透明的遮罩。
Android4.4(API19)以下的状态栏,默认会是黑色的
Android4.4至Android5.0的状态栏,会是全透明的
故,我们在设置的时候,需要三份styles.xml文件
styles文件package: res/values/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--引入透明主题-->
<style name="TranslucentTheme" parent="AppTheme"/>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
//标题栏的背景颜色
<item name="colorPrimary">@color/colorPrimary</item>
//状态栏的背景颜色
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
//各个控件被选中时候的颜色
<item name="colorAccent">@color/colorAccent</item>
//底部导航栏颜色
<item name="android:navigationBarColor">@color/navigationColor</item>
//toolbar的title颜色
<item name="android:textColorPrimary">@color/textColorPrimary</item>
//各个控件的默认颜色
<item name="android:colorControlNormal">@color/colorControlNormal</item>
</style>
package: res/values-19/styles.xml 开始有 android:windowTranslucentStatus 这个属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--android4.4开始有这个windowTranslucentStatus属性以上-->
<style name="TranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!--状态栏透明-->
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:fitsSystemWindows">true</item>
</style>
</resources>
上面,我们看到设置了fitsSystemWindow的属性。这个属性简单的来说,我们在设置应用布局的时候是否需要考虑系统窗口(状态栏、导航栏、输入法等)布局。对于状态栏来自动添加paddingTop,导航栏自动添加paddingBottom
package: res/values-21/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<!--让View根据系统窗口来调整自己的布局-->
<item name="android:fitsSystemWindows">true</item>
<!--Android 5.x开始需要把颜色设置为透明,否则导航栏会呈现系统默认的浅灰色-->
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
因为在5.0是半透明的,所以设置android:statusBarColor属性为透明的即可
效果图如下
2、java代码设置
修改MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(option);
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
}
}
这里先调用了getWindow.getDecorView()方法获取到了当前界面的DecorView,然后调用了它的setSystemUiVisibility()方法来设置UI元素的可见性,View.SYSTEM_UI_FLAG_FULLSCREEN表示全屏的意思,也就是将状态栏隐藏。而且根据Android的设计建议,ActionBar的是不应该独立于状态栏而单独显示的,因此状态栏隐藏了,我们也要将ActionBar通过hide()方法进行隐藏。
运行程序,效果可见:
现在总结一下,option具体有哪些值
Flag | 意义 |
---|---|
SYSTEM_UI_FLAG_LOW_PROFILE | 弱化状态栏和导航栏的图标 |
SYSTEM_UI_FLAG_HIDE_NAVIGATION | 隐藏导航栏,用户点击屏幕会显示导航栏 |
SYSTEM_UI_FLAG_FULLSCREEN | 隐藏状态栏 |
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | 拓展布局到导航栏后面 |
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | 拓展布局到状态栏后面 |
SYSTEM_UI_FLAG_LAYOUT_STABLE | 稳定的布局,不会随系统栏的隐藏、显示而变化 |
SYSTEM_UI_FLAG_IMMERSIVE | 沉浸模式,用户可以交互的界面 |
SYSTEM_UI_FLAG_IMMERSIVE_STICKY | 沉浸模式,用户可以交互的界面。同时,用户上下拉系统栏时,会自动隐藏系统栏 |
在Android5.0的机型上运行之后,显示的效果并不是我们xml设置出来的效果一样,也就是上面的状态栏没有了?不要慌,这是因为我们没有设置setStatusBarColor()状态栏为透明以及Flag为以下这种模式
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 拓展布局到状态栏后面
SYSTEM_UI_FLAG_LAYOUT_STABLE 稳定的布局,不会随系统栏的隐藏、显示而变化
实现代码如下
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= 21) { //5.0的机型上
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
}
}
以上的方式其实并不是沉浸式状态栏,我们估且可以把它叫做透明状态栏效果吧。
上面的方式已经将状态栏,标题栏去除了。那么如何设置下面的导航栏呢?其实也很简单,我们修改一下option里面的FLAG即可
具体代码如下
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= 21) { //5.0的机型上
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(option);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
}
}
运行之后,效果如下
现在看起来,效果不错。但是我们发现在这种模式下,我们触摸屏幕的任意位置的时候都会退出全屏
这显然不是我们想要的效果,因此,得实现一个真正的沉浸式模式
这时我们要重写Activity的onWindowFocusChanged()方法,然后加入逻辑就可以了
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus && Build.VERSION.SDK_INT >= 19) {
View decorView = getWindow().getDecorView();
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); //沉浸模式,用户可以交互的界面。同时,用户上下拉系统栏时,会自动隐藏系统栏
}
}
}
可以看到,界面默认情况下是全屏的,状态栏和导航栏都不会显示。而当我们需要用到状态栏或导航栏时,只需要在屏幕顶部向下拉,或者在屏幕右侧向左拉,状态栏和导航栏就会显示出来,此时界面上任何元素的显示或大小都不会受影响。过一段时间后如果没有任何操作,状态栏和导航栏又会自动隐藏起来,重新回到全屏状态。
这就是最标准的沉浸式模式。