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
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代表 添加到第一个
封装
设置状态栏颜色已经很普遍了,那考虑全面一点
- 可设置透明度
- 可设置是否覆盖
- 考虑是否包含navigationsbar
- 考虑5.0以上情况
StatusBarUtils.instance(this).setColor(color). setStyle(isFill ? StatusBarUtils.TYPE.FILL : StatusBarUtils.TYPE.NOMAL).init();
来一张效果图:
源码:ColorStatusBar
关于android 变色状态栏相关开源库
StatusBarCompat
StatusBarAdapt
更多相关文章
- 从Android 6.0源码的角度剖析View的事件分发机制
- Android消息机制源码解析(一)——消息的载体Message
- Android异步消息机制Handler详解,源码剖析(API 23)
- Android事件总线(四)源码解析otto
- Android中Canvas绘图基础详解(附源码下载)
- android 系统的开机启动流程源码解析(从linux 内核到android Laun
- Android主流三方库源码分析(二、深入理解Retrofit源码)