android 自4.4之后,开始支持半透明状态栏效果。
一般都是将布局延伸到状态栏下,并且保持和toolbar颜色一致,就是我们所说的变色状态栏。
比如我们经常用到的网易云音乐的状态栏处理 和 miui内置应用的状态栏处理都采用了这种方式,如下:
参考:Android 沉浸式状态栏攻略 让你的状态栏变色吧
关于变色状态栏的实现也非常的多,主要都是通过 4.4 之上的theme和fitsSystemWindows属性来实现的。
通过调整view的padding
来自动适应屏幕,具体表现:
设置为true时
<resources>
<style name="AppTheme" parent="@style/BaseAppTheme"> <item name="android:windowTranslucentStatus">true</item> </style>
</resources>
按照上面的设置,状态栏透明且显示的是activity的background
,如下如所示。这时候就需要在状态栏的位置设置一个颜色和 toolbar相同
的view 即可。这里可以使用开源库SystemBarTint
SystemBarTintManager tintManager=new SystemBarTintManager(this);
tintManager.setStatusBarTintResource(R.color.colorPrimaryDark);
tintManager.setStatusBarTintEnabled(true);
这里navigationView并没有沿伸到状态栏下,而是被状态栏盖住,和网易云音乐处理的还是优点差距,那么看一下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代表 添加到第一个
设置状态栏颜色已经很普遍了,那考虑全面一点
StatusBarUtils.instance(this).setColor(color).
setStyle(isFill ? StatusBarUtils.TYPE.FILL : StatusBarUtils.TYPE.NOMAL).init();
来一张效果图:
源码:ColorStatusBar
关于android 变色状态栏相关开源库
StatusBarCompat
StatusBarAdapt