“沉浸式状态栏”--完全理解沉浸模式

关于沉浸式状态栏一词的说法从何而来我们无从考证。但这确实是个错误的说法
先引用官方的一段话。

Immersive full-screen mode
To provide your app with a layout that fills the entire screen, the new SYSTEM_UI_FLAG_IMMERSIVE flag for setSystemUiVisibility()(when combined with SYSTEM_UI_FLAG_HIDE_NAVIGATION enables a new immersivefull-screen mode. While immersive full-screen mode is enabled, your activity continues to receive all touch events. The user can reveal the system bars with an inward swipe along the region where the system bars normally appear. This clears the SYSTEM_UI_FLAG_HIDE_NAVIGATION flag (and the SYSTEM_UI_FLAG_FULLSCREEN flag, if applied) so the system bars remain visible. However, if you'd like the system bars to hide again after a few moments, you can instead use the SYSTEM_UI_FLAG_IMMERSIVE_STICKY flag.

Translucent system bars

You can now make the system bars partially translucent with new themes, Theme.Holo.NoActionBar.TranslucentDecor and Theme.Holo.Light.NoActionBar.TranslucentDecor.By enabling translucent system bars, your layout will fill the area behind the system bars, so you must also enable fitsSystemWindows for the portion of your layout that should not be covered by the system bars.
If you're creating a custom theme, set one of these themes as the parent theme or include the windowTranslucentNavigation and windowTranslucentStatus style properties in your theme.

以上是官网对于状态栏的相关描述。那么什么意思呢?

  • Immersive full-screen mode (沉浸式全屏模式)
    隐藏status bar(状态栏)使屏幕全屏,让Activity接收所有的(整个屏幕的)触摸事件。
  • Translucent system bars (透明化系统栏)
    使得布局侵入系统栏的后面,必须启用fitsSystemWindows属性来调整布局才不至于被系统栏覆盖。
    看到这里我要说:其实根本没有什么沉浸式状态栏,这就是一种错误的说法,错误的概念。
    如果到这里你还是有点迷糊那么我们再看两幅效果图,你就明白了。

沉浸式全屏模式:activity 占据整个屏幕,用户交互时(拖动状态栏所在的位置)才会出现状态栏和导航栏

沉浸全屏模式

透明状态栏模式:状态栏和导航栏依然可见但是呈现半透明状态
透明状态栏模式

注意:以上效果是在原生开发系统上的效果,部分国产定制系统可能略有差异。请注意

实现方式:

其一Translucent Bar是4.4开始有的特性;其二是5.0开始,Google推出Material Design,使用Theme.Material(MD主题)或Theme.AppCompat主题并至少设置ColorPrimaryDark属性就可以实现status bar半透明效果,所以本文只讨论API19以上操作系统

  1. 通过Theme 方式实现,官网有说明android 中文官网
  • 直接继承官方Theme: 在Android API 19以上可以使用****.TranslucentDecor***有关的主题,自带相应半透明效果,Theme.Holo.NoActionBar.TranslucentDecor和Theme.Holo.Light.NoActionBar.TranslucentDecor两种主题为新增加的,所以要新建values-v19文件夹并创建styles文件。
 <style name="translusent"parent="android:Theme.Holo.Light.NoActionBar.TranlucentDecor">
</style>

在AndroidManifest 中设置使用该theme

<activity
     android:name=".translucent.TranslusentThemeActivity"
     android:label="@string/translucent_theme"
     android:theme="@style/translusent">
 </activity>
  • 自定义主题Theme:继承新主题时发现。这两个新加的主题就是将windowTranslucentStatus ,windowTranslucentNavigation都设为true即可实现透明效果,那么只要我们自定义的主题也实现这两个属性即可。
    在value-v19中新建style,代码如下
<style name="translusent" parent="Theme.AppCompat.Light.DarkActionBar">
  <item name="android:windowTranslucentStatus">true</item>
  <item name="android:windowTranslucentNavigation">true</item>
  </style>

由于 5.x开始需要把颜色设置透明 ,所以我们必须新建个values-v21,并新建下面的主题

<style name="translusent" parent="Theme.AppCompat.Light.DarkActionBar">
 <item name="android:windowTranslucentStatus">true</item>
 <item name="android:windowTranslucentNavigation">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
 <!--Android 5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色-->   
    </style>
总结:由主题来实现有一定的不确定性(少数情况下),可能因为定制机器。模拟器等原因而达不到预期效果。但也不失为一种简单方便的实现方式
  1. 通过java代码实现。下面我逐步实现
    首先我们看下整体的代码
public class TranslusentActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.translucent);
        /**
         * 由于21以下不能设置statusbar和NavigationBar的颜色所以实现透明化系统栏效果,仍然可以实现沉浸全屏模式
         * */
        if (Build.VERSION.SDK_INT >= 21) {
            int option = getOption(6);
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility(option);

            getWindow().setStatusBarColor(Color.TRANSPARENT);//设置statusbar为透明色
            getWindow().setNavigationBarColor(Color.TRANSPARENT);//设置NavigationBar为透明色
        }
        ActionBar actionBar = getSupportActionBar();
        actionBar.hide();
    }
    /**
     * 由于各个flag都有相互制约性,不是单纯的相互叠加效果。
     * 所以也不必再在意每个flag的作用
     *
     * */
    private int getOption(int type) {
        int option = 0;
        switch (type) {
            case 0:
                //隐藏statusbar的效果,当与用户交互时flag失效
                option= View.SYSTEM_UI_FLAG_FULLSCREEN;
                break;
            case 1:
                //隐藏导航栏,当与用户交互时(如拖动)该flag失效
                option= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
                break;
            case 2:
                //全部隐藏都不透明,当有用户交互,比如点击拖动。flag就会失效
                option= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN;
                break;
            case 3:
                //为设置statusbar实现透明铺垫,将statusbar移动到图层的最上面,
                // 当设置statusbar为透明色的时候就可以实现沉浸效果
                // 再调用setStatusBarColor
                // 整个statusbar显示为透明色
                option=View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
                break;
            case 4://半透明效果
                //这个模式也是为实现透明做铺垫,将statusbar,Navigationbar 移动到图层的最上面,
                // 当设置statusbar,NavigationBar设置为透明色的时候就可以实现沉浸效果
                // 再调用setStatusBarColor,setNavigationBarColor,设置为透明色。即可
                option = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
                break;

            case 5:
                //隐藏导航栏,有SYSTEM_UI_FLAG_IMMERSIVE,
                // 拖动时隐藏导航栏的flag依然有效。
                // 没有SYSTEM_UI_FLAG_IMMERSIVE,隐藏导航栏的flag立刻失效
                //SYSTEM_UI_FLAG_IMMERSIVE_STICKY和SYSTEM_UI_FLAG_IMMERSIVE效果相同,
                // 只是几秒钟后隐藏导航栏的flag 又会生效
                //这时候如果设置setStatusBarColor颜色为透明色,
                // statusbar只会显示为白色。。因为最下面的底色不透明
                option=View.SYSTEM_UI_FLAG_IMMERSIVE
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
                break;
            case 6:
                //综合应用,当交互时导航栏,statusbar出现。失去焦点时消失
                option=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;

                break;


            default:
                //隐藏statusbar的效果,当与用户交互时flag失效
                option= View.SYSTEM_UI_FLAG_FULLSCREEN;
                break;
        }
        return option;
    }
 /**
   * 19以上实现沉浸式全屏模式
   */
/*
    @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);
        }
    }*/
}

调用view的setSystemUiVisibility(int option) 方法给View设置不同的flag,从而实现不同的布局效果
下面我们一步步分析,不同的flag及flag组合

  • case 0:View.SYSTEM_UI_FLAG_FULLSCREEN;
    隐藏statusbar当与用户交互时flag失效 ,此时若设置statusbar的颜色为透明,则显示为白色
    隐藏statusbar效果图
  • case 1: View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
    隐藏Navigation当与用户交互时flag失效,
    隐藏Navigationbar效果图
  • **case2: **View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
    View.SYSTEM_UI_FLAG_FULLSCREEN;
    隐藏statusbar和Navigationbar全部隐藏,当与用户交互时flag失效。


    隐藏Navigationbar和statusbar效果图
  • case 3:View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
    为设置statusbar实现透明铺垫,将statusbar移动到图层的最上面,当设置statusbar为透明色的时候就可以实现沉浸效果
    实现statusbar透明效果
  • case 4:View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    |View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
    这个模式也是为实现透明做铺垫,将statusbar,Navigationbar 移动到图层的最上面,当设置statusbar,NavigationBar设置为透明色的时候就可以实现沉浸效果

    statusbar、Navigationbar全透明效果

  • case 5: View.SYSTEM_UI_FLAG_IMMERSIVE
    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
    Kitkat新加入的Flag, 沉浸模式, 可以隐藏掉status跟navigation bar, 并且在第一次会弹泡提醒, 它会覆盖掉之前两个隐藏bar的标记, 并且在bar出现的位置滑动可以呼出bar

  • case 6 : View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
    隐藏导航栏,如有 SYSTEM_UI_FLAG_IMMERSIVE_STICKY 修饰 ,用户交互时Navigation 会出现,当失去焦点时会再次隐藏

  • **case 7: ** 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;
    综合应用,当;用户交互时出现透明的statausbar和Navigationbar,当失去焦点时再次隐藏statusbar和Navigationbar

以上的情况基本涵盖了开发中的大部分情况,很多的flag都具有相互依懒性,所以没有必要去搞清楚每个flag的意思。需要的时候,当做工具类用就可以了。
由于21以下不能设置statusbar和NavigationBar的颜色,不能实现透明化系统栏效果,按着默认颜色显示。但仍然可以实现沉浸全屏模式 ,所以这里做了API版本的判断。 如果你要在API19以上用,只需要修改API版本判断即可(当然那时候状态栏、导航栏按着默认颜色显示)。代码中被我注释掉的部分即是

    //19以上实现沉浸式全屏模式
    @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);
        }
    }

源码由于和另一个Demo写在一起的,所以暂时没上传,后续另一篇文章完成以后会上传的


多谢以下几位大神的无私奉献,如有错误欢迎指正,欢迎转载,但请注明出处,谢谢
沉浸式状态栏引发的血案
Android状态栏微技巧,带你真正理解沉浸式模式-郭神

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容