沉浸在状态栏的世界

我们知道在日常开发中,当我们拿到UI给我们的设计图时,咋一看好像界面也就那样,没啥难点,但是当我们着手的时候,噫…这是啥? 是不是UI把标题画掉了,怎么没看到标题??然后就去一通询问,最后被告知不是没有标题,而是标题是透明的,用一张背景图作为整体取代了标题。wtf…算了,还是好好研究一下这是什么玩意吧!

单纯的改变状态栏的颜色就很容易,所以在这里就不做介绍了哈,重点讲解一下透明状态栏(也就是传说中的沉浸式)。

方法一:通过设置主题Theme来实现状态栏透明
由于API21之后(也就是安卓5.0之后)系统会默认的覆盖一层半透明遮罩,而且为了保证4.4之前的系统正常使用,因此需要三分styles文件。即默认的values(不设置状态栏透明)、values-v19、values-v21(解决半透明遮罩问题)。

<!--values-->
    <style name="TranslucentTheme" parent="AppTheme"></style>
    
<!--values-v19。v19 开始有 android:windowTranslucentStatus 这个属性-->
    <style name="TranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowTranslucentNavigation">true</item>
    </style>

<!--values-v21。5.0 以上提供了 setStatusBarColor()  方法设置状态栏颜色。-->
    <style name="TranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowTranslucentNavigation">true</item>
        <item name="android:windowTranslucentStatus">true</item>
        <!--Android 5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色-->
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>

这里写图片描述 这里写图片描述
由图可见设置状态栏透明之后布局的内容就会延伸到状态栏,但是有些场景下我们还是需要保留状态栏那块区域的,解决方法有三种:

1.通过在布局的最外层设置 android:fitsSystemWindows=“true” 属性。当然,也可以通过代码设置:

	/**
     * 动态设置页面最外层布局 FitsSystemWindows 属性
     * @param activity
     * @param isFit
     */
    public static void setFitSystemWindow(Activity activity,boolean isFit){
        ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
        View rootView = contentView.getChildAt(0);
        if (rootView != null && Build.VERSION.SDK_INT >= 14) {
            rootView.setFitsSystemWindows(isFit);
        }
    }

通过设置FitsSystemWindows 属性保留状态栏的paddingTop后,在设置颜色就能实现想要的效果了,但是这样的话只能通过设置最外层布局的颜色来达到效果,比如设置状态栏为红色,只要设置最外层布局背景为红色即可,但是这样的话就让整个布局的背景都变成了红色,所以子布局就得设置为白色或其他颜色,这样就会过渡绘制,影响性能。而且设置了fitsSystemWindows=true 属性的页面,在点击 EditText 调出 软键盘时,整个视图都会被顶上去。

2.在布局里面添加一个占位视图

<View
        android:id="@+id/status_bar_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary" />

利用反射机制获取状态栏的高度:

	/**
     * 利用反射获取状态栏高度
     */
    public static int getStatusBarHeight(Activity activity) {
        int result = 0;
        //获取状态栏高度的资源id
        int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            result = activity.getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }

设置占位视图的高度:

		statusBarView = findViewById(R.id.status_bar_view);
        ViewGroup.LayoutParams params = statusBarView.getLayoutParams();
        params.height = StatusBarUtil.getStatusBarHeight(this);
        statusBarView.setLayoutParams(params);

除了在布局中添加占位view之外,当然也可以在代码中动态添加,推荐在代码中添加,封装出来更方便使用:

	/**
     * 添加状态栏占位视图 
     * * @param activity
     */
    public static void addStatusViewWithColor(Activity activity, int color) {
        ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
        View statusBarView = new View(activity);
        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
        statusBarView.setBackgroundColor(color);
        contentView.addView(statusBarView, lp);
    }

3.代码中设置paddingTop并添加占位状态栏:
手动给根视图设置一个paddingTop,高度为状态栏高度,相当于手动实现了fitsSystemWindows=true的效果,然后再在根视图加入一个占位视图,其高度也设置为状态栏高度。

	/**
     * 设置 paddingTop 并添加占位状态栏
     * * @param activity
     */
    public static void addStatusBarView(Activity activity, int color) {
        //设置paddingTop
        ViewGroup rootView = (ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content);
        rootView.setPadding(0, getStatusBarHeight(activity), 0, 0);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //5.0 以上直接设置状态栏颜色
            activity.getWindow().setStatusBarColor(color);
        } else {
            //根布局添加占位状态栏
            ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
            View statusBarView = new View(activity);
            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
            statusBarView.setBackgroundColor(color);
            decorView.addView(statusBarView, lp);
        }
    }

通过这种方法达到沉浸式的效果后面也可以很方便地拓展出渐变色的状态栏。

附上效果图:
这里写图片描述 这里写图片描述

方法二:在代码中动态设置方法一中Theme中的属性

方案一:

	/**
     * 动态设置Theme实现透明状态栏
     * * @param activity
     */
    public static void setTranslucentTheme(Activity activity, int color) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
            int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Window window = activity.getWindow();
                WindowManager.LayoutParams attributes = window.getAttributes();
                attributes.flags |= flagTranslucentNavigation;
                window.setAttributes(attributes);
                activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
            } else {
                Window window = activity.getWindow();
                WindowManager.LayoutParams attributes = window.getAttributes();
                attributes.flags |= flagTranslucentStatus | flagTranslucentNavigation;
                window.setAttributes(attributes);
            }
        }
    }

运行后会发现,在 5.x 以下导航栏透明是可以生效的,但 5.x 以上导航栏会变灰色(正常情况下我们期望导航栏保持默认颜色黑色不变),但是因为设置FLAG_TRANSLUCENT_NAVIGATION所以即使代码中设置getWindow().setNavigationBarColor(Color.BLACK); 也是不起作用的。但如果不设置该 FLAG ,状态栏又无法被置为隐藏和设置透明。

方案二:
通过设置FLAG,让应用内容占用系统状态栏的空间,经测试该方式不会影响对导航栏的设置。

	/**
     * 设置全屏,设置状态栏透明
     * * @param activity
     */
    public static void setFullScreenTranslucent(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                //5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色
                Window window = activity.getWindow();
                View decorView = window.getDecorView();
                //两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间
                int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
                decorView.setSystemUiVisibility(option);
                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                window.setStatusBarColor(Color.TRANSPARENT);
                //导航栏颜色也可以正常设置
//                window.setNavigationBarColor(Color.TRANSPARENT);
            } else {
                Window window = activity.getWindow();
                WindowManager.LayoutParams attributes = window.getAttributes();
                int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
                int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
                attributes.flags |= flagTranslucentStatus;
//                attributes.flags |= flagTranslucentNavigation;
                window.setAttributes(attributes);
            }
        }
    }

通过此方案设置之后运行效果如同上面添加占位视图,便不再附上重复截图啦!

总结:
沉浸式状态栏这块磨人的内容大家要动手去实践,当你在不同的安卓系统上都试着去改变一下状态栏,你就会更深刻的了解到这块知识点,就不会感到懵逼了,其实吧,当你掌握了如何让状态栏变成透明的你也就基本能胜任关于状态栏系列的问题啦。好啦,此篇章就到此结束咯。希望能为大家伙解惑!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值