美文网首页Android笔记本Material Design
Android 沉浸式状态栏的实现

Android 沉浸式状态栏的实现

作者: 骚年一起奋斗吧 | 来源:发表于2018-12-06 14:21 被阅读33次

    沉浸式到底是一种什么感觉呢?

    用户完全沉浸的体验,使用户有一种置身于虚拟世界之中的感觉。

    我真的很难理解这是一种什么感觉。。。。

    直到读了一下郭霖大神的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); //沉浸模式,用户可以交互的界面。同时,用户上下拉系统栏时,会自动隐藏系统栏
            }
        }
    
    }
    

    可以看到,界面默认情况下是全屏的,状态栏和导航栏都不会显示。而当我们需要用到状态栏或导航栏时,只需要在屏幕顶部向下拉,或者在屏幕右侧向左拉,状态栏和导航栏就会显示出来,此时界面上任何元素的显示或大小都不会受影响。过一段时间后如果没有任何操作,状态栏和导航栏又会自动隐藏起来,重新回到全屏状态。

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

    相关文章

      网友评论

        本文标题:Android 沉浸式状态栏的实现

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