记得之前有朋友在留言里让我写一篇关于沉浸式状态栏的文章,正巧我确实有这个打算,那么本篇就给大家带来一次沉浸式状态栏的微技巧讲解。

其实说到沉浸式状态栏这个名字我也是感到很无奈,真不知道这种叫法是谁先发起的。因为Android官方从来没有给出过沉浸式状态栏这样的命名,只有沉浸式模式(Immersive Mode)这种说法。而有些人在没有完全了解清楚沉浸模式到底是什么东西的情况下,就张冠李戴地认为一些系统提供的状态栏操作就是沉浸式的,并且还起了一个沉浸式状态栏的名字。

比如之前就有一个QQ群友问过我,像饿了么这样的沉浸式状态栏效果该如何实现?

这个效果其实就是让背景图片可以利用系统状态栏的空间,从而能够让背景图和状态栏融为一体。

本篇文章当中我会教大家如何实现这样的效果,但这个真的不叫沉浸式状态栏。因此,这算是一篇技术+普及的文章吧,讲技术的同时也纠正一下大家之前错误的叫法。

什么是沉浸式?

先来分析一下叫错的原因吧,之所以很多人会叫错,是因为根本就不了解沉浸式是什么意思,然后就人云亦云跟着叫了。那么沉浸式到底是什么意思呢?

根据百度百科上的定义,沉浸式就是要给用户提供完全沉浸的体验,使用户有一种置身于虚拟世界之中的感觉。

比如说现在大热的VR就是主打的沉浸式体验。

那么对应到Android操作系统上面,怎样才算是沉浸式体验呢?这个可能在大多数情况下都是用不到的,不过在玩游戏或者看电影的时候就非常重要了。因为游戏或者影视类的应用都希望能让用户完全沉浸在其中,享受它们提供的娱乐内容,但如果这个时候在屏幕的上方还显示一个系统状态栏的话,可能就会让用户分分钟产生跳戏的感觉。

那么我们来看一下比较好的游戏都是怎么实现的,比如说海岛奇兵:

海岛奇兵的这种模式就是典型的沉浸式模式,它的整个屏幕中显示都是游戏的内容,没有状态栏也没有导航栏,用户玩游戏的时候就可以完全沉浸在游戏当中,而不会被一些系统的界面元素所打扰。

然后我们再来看一下爱奇艺的实现:

 
同样也是类似的,爱奇艺将整个屏幕作为影视的展示区,用户在看电影的时候眼中就只会有电影的内容,这样就不会被其他一些无关的东西所分心。

这才是沉浸式模式的真正含义,而所谓的什么沉浸式状态栏纯粹就是在瞎叫,完全都没搞懂“沉浸式” 这三个字是什么意思。

不过虽然听上去好像是很高大上的沉浸式效果,实际看上去貌似就是将内容全屏化了而已嘛。没错,Android沉浸式模式的本质就是全屏化,不过我们今天的内容并不仅限于此,因为还要实现饿了么那样的状态栏效果。那么下面我们就开始来一步步学习吧。

隐藏状态栏 

可以看到,有状态栏、ActionBar、导航栏等。而打造沉浸式模式的用户体验,就是要将这些系统元素全部隐藏,只留下主体内容部分。

比如说我现在新建了一个空项目,然后修改布局文件中的代码,在里面加入一个ImageView,如下所示:

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"> <ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/bg"
android:scaleType="centerCrop" /> </RelativeLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这里将ImageView的宽和高都设置成match_parent,让图片充满屏幕。现在运行一下程序,效果如下图所示。

 
如果你将图片理解成游戏或者电影界面的话,那这个体验离沉浸式就差得太远了,至少状态栏和ActionBar得要隐藏起来了吧?没关系,我们一步步进行优化,并且在优化中学习。

隐藏状态栏和ActionBar的方式在4.1系统之上和4.1系统之下还是不一样的,这里我就不准备考虑4.1系统之下的兼容性了,因为过于老的系统根本就没有提供沉浸式体验的支持。

修改MainActivity中的代码,如下所示:

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();
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这里先调用getWindow().getDecorView()方法获取到了当前界面的DecorView,然后调用它的setSystemUiVisibility()方法来设置系统UI元素的可见性。其中,SYSTEM_UI_FLAG_FULLSCREEN表示全屏的意思,也就是会将状态栏隐藏。另外,根据Android的设计建议,ActionBar是不应该独立于状态栏而单独显示的,因此状态栏如果隐藏了,我们同时也需要调用ActionBar的hide()方法将ActionBar也进行隐藏。

现在重新运行一下程序,效果如下图所示。

 
这样看上去就有点沉浸式效果的模样了。

虽说这才是正统的沉浸式含义,但有些朋友可能想实现的就是饿了么那样的状态栏效果,而不是直接把整个系统状态栏给隐藏掉,那么又该如何实现呢?

其实也很简单,只需要借助另外一种UI Flag就可以了,如下所示:

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= 21) {
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();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

首先需要注意,饿了么这样的效果是只有5.0及以上系统才支持,因此这里先进行了一层if判断,只有系统版本大于或等于5.0的时候才会执行下面的代码。

接下来我们使用了SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_STABLE,注意两个Flag必须要结合在一起使用,表示会让应用的主体内容占用系统状态栏的空间,最后再调用Window的setStatusBarColor()方法将状态栏设置成透明色就可以了。

现在重新运行一下代码,效果如下图所示。

 
可以看到,类似于饿了么的状态栏效果就成功实现了。

再声明一次,这种效果不叫沉浸式状态栏,也完全没有沉浸式状态栏这种说法,我们估且可以把它叫做透明状态栏效果吧。

隐藏导航栏 
现在我们已经成功实现隐藏状态栏的效果了,不过屏幕下方的导航栏还比较刺眼,接下来我们就学习一下如何将导航栏也进行隐藏。

其实实现的原理都是一样的,隐藏导航栏也就是使用了不同的UI Flag而已,修改MainActivity中的代码,如下所示:

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(option);
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里我们同时使用了SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN,这样就可以将状态栏和导航栏同时隐藏了。现在重新运行一下程序,效果如图所示。 

这次看上去好像终于是完全全屏化了,但其实上这离真正的沉浸式模式还差得比较远,因为在这种模式下,我们触摸屏幕的任意位置都会退出全屏。 
 
这显然不是我们想要的效果,因此这种模式的使用场景比较有限。

除了隐藏导航栏之外,我们同样也可以实现和刚才透明状态栏类似的效果,制作一个透明导航栏:

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= 21) {
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
getWindow().setNavigationBarColor(Color.TRANSPARENT);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这里使用了SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,表示会让应用的主体内容占用系统导航栏的空间,然后又调用了setNavigationBarColor()方法将导航栏设置成透明色。现在重新运行一下程序,效果如下图所示。 

真正的沉浸式模式 
虽说沉浸式导航栏这个东西是被很多人误叫的一种称呼,但沉浸式模式的确是存在的。那么我们如何才能实现像海岛奇兵以及爱奇艺那样的沉浸式模式呢?

首先你应该确定自己是否真的需要这个功能,因为除了像游戏或者视频软件这类特殊的应用,大多数的应用程序都是用不到沉浸式模式的。

当你确定要使用沉浸式模式,那么只需要重写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);
}
} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

沉浸式模式的UI Flag就这些,也没什么好解释的,如果你需要实现沉浸式模式,直接将上面的代码复制过去就行了。需要注意的是,只有在Android 4.4及以上系统才支持沉浸式模式,因此这里也是加入了if判断。

另外,为了让我们的界面看上去更像是游戏,这里我将MainActivity设置成了横屏模式:

<activity android:name=".MainActivity"
android:screenOrientation="landscape">
...
</activity>
  • 1
  • 2
  • 3
  • 4

这样我们就实现类似于海岛奇兵和爱奇艺的沉浸式模式效果了,如下图所示。 
 
可以看到,界面默认情况下是全屏的,状态栏和导航栏都不会显示。而当我们需要用到状态栏或导航栏时,只需要在屏幕顶部向下拉,或者在屏幕右侧向左拉,状态栏和导航栏就会显示出来,此时界面上任何元素的显示或大小都不会受影响。过一段时间后如果没有任何操作,状态栏和导航栏又会自动隐藏起来,重新回到全屏状态。

这就是最标准的沉浸式模式。

android 动态控制状态栏显示和隐藏的方法实例

android想要应用运行时全屏有一种方法是在activity的onCreat方法中加入如下代码:getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
WindowManager.LayoutParams.FLAG_FULLSCREEN);并且需要在setContentView()之前,否则无效过。从这么多的苛刻条件可以看出这种方法无法满足动态控制。

下面的方法可以满足这个需要。调用View的 setSystemUiVisibility()

方法,其参数如下:

View.SYSTEM_UI_FLAG_FULLSCREEN, //全屏,状态栏和导航栏不显示 
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION, //隐藏导航栏 
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, //全屏,状态栏会盖在布局上 
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 
View.SYSTEM_UI_FLAG_LAYOUT_STABLE, 
View.SYSTEM_UI_FLAG_LOW_PROFILE, 
View.SYSTEM_UI_FLAG_VISIBLE, //显示状态栏和导航栏 
View.SYSTEM_UI_LAYOUT_FLAGS

Android colorPrimary colorPrimaryDark colorAccent

Android design theme color

<style name="AppTheme.NoActionBar">
<!--状态栏颜色-->
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<!--控制各个控件被选中时的颜色-->
<item name="colorAccent">@color/colorAccent</item>
<!--页面背景色-->
<item name="android:windowBackground">@color/windowBackg</item>
<!--底部导航栏颜色-->
<item name="android:navigationBarColor">@color/navigationColor</item>
<!--Appbar背景色-->
<item name="android:colorPrimary">@color/colorPrimary</item>
<!--ToolBar上的Title颜色-->
<item name="android:textColorPrimary">@color/textColorPrimary</item>
<!--各个控制控件的默认颜色-->
<item name="android:colorControlNormal">@color/colorControlNormal</item>
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

 
Android design theme color 保存在res/values/styles.xml下

<resources>

    <!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style> </resources>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

color rgb值保存在res/values/colors.xml下

<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#000000</color>
<color name="colorAccent">#ffffff</color>
</resources>

Android动态控制状态栏显示和隐藏的更多相关文章

  1. android 动态控制状态栏显示和隐藏

    方法一:(经试验无效,但网上广为流传,也许是我使用方法不当,有待进一步验证……) android想要应用运行时全屏有一种方法是在activity的onCreat方法中加入如下代码: getWindow ...

  2. Android监听键盘显示和隐藏

    问题概况:横板cocos2dx游戏,点击输入框弹出键盘时,界面要求跟随网上平易,不能挡住输入框.这种问题只出现在非全屏键盘到情况下. 方案1:mainActivity重写onconfiguration ...

  3. Android控件显示和隐藏

    Android控件都有visibility属性,该属性有三个可能值:visible.invisible.gone.可以通过预设或是Java程序控制这些控件的显示或隐藏. 一.在XML配置文件设置 可见 ...

  4. IOS 状态栏 显示与隐藏网络活动状态

    IOS中显示和隐藏状态栏的网络活动标志 //在向服务端发送请求状态栏显示网络活动标志: [[UIApplication sharedApplication] setNetworkActivityInd ...

  5. android如何调用显示和隐藏系统默认的输入法(一)

    1.调用显示系统默认的输入法 方法一. InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_MET ...

  6. Android学习笔记显示和隐藏ActionBar

    要在应用中使用ActionBar 需要android:minSdkVersion:11以上,现在基本都可以用了 创建Android项目如果不做特殊设置默认都带有ActionBar 如果不想要Actio ...

  7. Android输入法的显示与隐藏

    显示输入法: public void ShowSoftInput(View v) { // v 接受输入的控件 mInputMethodManager = (InputMethodManager) ( ...

  8. android屏蔽状态栏显示

    framework/base/packages/SystemUI/res/layout/status_bar_expanded.xml 要屏蔽哪个设置哪个属性为: android:visibility ...

  9. ionic 解决APP安装到android上 状态栏显示黑色

    首先移除原本的 cordova-plugin-statusbar 运行命令: cordova plugin rm cordova-plugin-statusbar 最后需要重新安装: cordova ...

随机推荐

  1. 外显子分析弹错解决方案:Exception in thread "main" picard.PicardException: New reference sequence does not contain a matching contig for NC_007605

    最近从公共数据库下载了一堆bam文件和reference 基因组文件,重新分析外显子流程时,跑出了“Exception in thread "main" picard.Picard ...

  2. 编译RocketMQ

    目前最新版本为 官方没有提供可执行的安装包,只提供了maven项目,去GitHub下载 点击Download ZIP 就可以了,如果你安装了版本控制工具 SVN 或者 GIT 就可以使用它上边的 UR ...

  3. Tarjan 模板,高级并查集

    第一个模板有误!!!! 请见谅!!! 要怪就怪HDU吧,竟然让我过了 第二个模板是正确的.请翻到下面看更新 HDU 1269 评论区居然有人说用并查集过了,其实回想一下 求无向图的连通分量,就是并查集 ...

  4. httpd配置文件详解及实例

    httpd配置文件详解及实例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.http协议的组成 http协议是C/S架构:我们可以把浏览器(如:IE,Firefox,Safar ...

  5. JavaSE学习总结(十五)—— Java反射与注解

    一.静态语言与动态语言 静态类型语言:是指在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型,某些具有类型推导能力的现代语言可能能够部分减轻这个要求.强类型 动态 ...

  6. Hive记录-Sqoop常用命令

    1.sqoop是什么 Sqoop是一款开源的数据迁移工具,主要用于Hadoop(Hive)与传统的关系型数据库(mysql...)相互之间的数据迁移. 2.sqoop的特点 sqoop的底层实现是ma ...

  7. SQL记录-小表join大表查询例子

  8. 《高性能Mysql》讲聚簇索引

    <高性能Mysql>原文 聚簇索引如下图为聚簇所有的存储方式,聚簇实际不是一种索引,而是一种数据的存储方式,InnoDB的聚簇事假在同一个结构中保存了B-Tree索引和数据行. 当表有聚簇 ...

  9. Netty 实现HTTP文件服务器

    一,需求 文件服务器使用HTTP协议对外提供服务.用户通过浏览器访问文件服务器,首先对URL进行检查,若失败返回403错误:若通过校验,以链接的方式打开当前目录,每个目录或文件都以超链接的形式展现,可 ...

  10. This dependency was not found: * !!vue-style-loader!css-loader?

    npm install stylus-loader css-loader style-loader --save-dev 猜测这两个组件发布时是不需要的,所以要加上-dev