Android变色状态栏的实现

概述

android 自4.4之后,开始支持半透明状态栏效果。
一般都是将布局延伸到状态栏下,并且保持和toolbar颜色一致,就是我们所说的变色状态栏。

比如我们经常用到的网易云音乐的状态栏处理 和 miui内置应用的状态栏处理都采用了这种方式,如下:
网易云音乐效果

实现

参考:Android 沉浸式状态栏攻略 让你的状态栏变色吧

关于变色状态栏的实现也非常的多,主要都是通过 4.4 之上的theme和fitsSystemWindows属性来实现的。

fitsSystemWindows

通过调整view的padding来自动适应屏幕,具体表现:
设置为true时

  • api>19时,view的paddingTop=status bar 的高度保障content正常显示。
  • api<19时,paddingTop =0 ,因为content并没有沿伸到status bar中。

style

  • values-v19/styles.xml
<resources>

    <style name="AppTheme" parent="@style/BaseAppTheme">
        <item name="android:windowTranslucentStatus">true</item>
    </style>
</resources>

按照上面的设置,状态栏透明且显示的是activity的background,如下如所示。这时候就需要在状态栏的位置设置一个颜色和 toolbar相同的view 即可。这里可以使用开源库SystemBarTint

状态栏颜色和activity一致

SystemBarTint:

 SystemBarTintManager tintManager=new SystemBarTintManager(this);
        tintManager.setStatusBarTintResource(R.color.colorPrimaryDark);
        tintManager.setStatusBarTintEnabled(true);

最终效果如下图:
效果图

这里navigationView并没有沿伸到状态栏下,而是被状态栏盖住,和网易云音乐处理的还是优点差距,那么看一下SystemBarTint源码吧。

SystemBarTint源码解析

扒开SystemBarTint的源码,我们可以看到作者的设计思路也是这样的,

首先,通过反射获取是否存在navigation bar,

static {
        // Android allows a system property to override the presence of the navigation bar.
        // Used by the emulator.
        // See https://github.com/android/platform_frameworks_base/blob/master/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#L1076
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            try {
                Class c = Class.forName("android.os.SystemProperties");
                Method m = c.getDeclaredMethod("get", String.class);
                m.setAccessible(true);
                sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys");
            } catch (Throwable e) {
                sNavBarOverride = null;
            }
        }
    }

这里有一个SystemBarConfig类,主要是记录设备的屏幕参数的,主要有statusbar的信息和navigationsbar的信息和是否包含navigationsbar等等。

然后,在构造函数中,通过获取activity的style来获取是否设置了Translucent主题

// check theme attrs
            int[] attrs = {android.R.attr.windowTranslucentStatus,
                    android.R.attr.windowTranslucentNavigation};
            TypedArray a = activity.obtainStyledAttributes(attrs);
            try {
                mStatusBarAvailable = a.getBoolean(0, false);
                mNavBarAvailable = a.getBoolean(1, false);
            } finally {
                a.recycle
                }

最终调用,通过设置好的Color 或者Drawable 来 添加(mStatusBarTintView)

private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {
        mStatusBarTintView = new View(context);
        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());
        params.gravity = Gravity.TOP;
        if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {
            params.rightMargin = mConfig.getNavigationBarWidth();
        }
        mStatusBarTintView.setLayoutParams(params);
        mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
        mStatusBarTintView.setVisibility(View.GONE);
        decorViewGroup.addView(mStatusBarTintView);
    }

    private void setupNavBarView(Context context, ViewGroup decorViewGroup) {
        mNavBarTintView = new View(context);
        LayoutParams params;
        if (mConfig.isNavigationAtBottom()) {
            params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getNavigationBarHeight());
            params.gravity = Gravity.BOTTOM;
        } else {
            params = new LayoutParams(mConfig.getNavigationBarWidth(), LayoutParams.MATCH_PARENT);
            params.gravity = Gravity.RIGHT;
        }
        mNavBarTintView.setLayoutParams(params);
        mNavBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
        mNavBarTintView.setVisibility(View.GONE);
        decorViewGroup.addView(mNavBarTintView);
    }

经过分析,这里是因为这行代码

// 在跟布局添加mStatusBarTintView
   decorViewGroup.addView(mStatusBarTintView);

只需要修改上述代码如下即可

private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {

        ViewGroup root = (ViewGroup) decorViewGroup.findViewById(android.R.id.content);

        mStatusBarTintView = new View(context);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());
        params.gravity = Gravity.TOP;
        if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {
            params.rightMargin = mConfig.getNavigationBarWidth();
        }
        mStatusBarTintView.setLayoutParams(params);
        mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
        mStatusBarTintView.setVisibility(View.GONE);
        //在content中添加mStatusBarTintView
        root.addView(mStatusBarTintView, 0);
    }

这里涉及到一个问题:addView(child) 和addView(child,0)的区别:

前者调用的是addView(child,-1),传入的 -1代表直接添加到 view的最后
传入0代表 添加到第一个

封装

设置状态栏颜色已经很普遍了,那考虑全面一点,本例源码地址ColorStatusBar

  • 可设置透明度
  • 可设置是否覆盖
  • 考虑是否包含navigationsbar
  • 考虑5.0以上情况
StatusBarUtils.instance(this).setColor(color).
                setStyle(isFill ? StatusBarUtils.TYPE.FILL : StatusBarUtils.TYPE.NOMAL).init();

来一张效果图:
ColorStatusBar

关于android 变色状态栏相关开源库
StatusBarCompat
StatusBarAdapt

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值