美文网首页其它androidAndroid之界面
“沉浸式状态栏”--完全理解沉浸模式

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

作者: ifjgm | 来源:发表于2017-02-22 21:14 被阅读723次

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

    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状态栏微技巧,带你真正理解沉浸式模式-郭神

    相关文章

      网友评论

      本文标题: “沉浸式状态栏”--完全理解沉浸模式

      本文链接:https://www.haomeiwen.com/subject/tsamwttx.html