在 Android4.4 之后,Android Window支持了一些新的属性,其中有两个是这样的 .
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
正如它们的变量名的意思,使用这两个属性,可以使得状态栏和导航栏变为透明,导航栏指的就是Android下方的三大按键,当然只使用第一个属性也可以达到今天所要完成的效果。下面的示例代码将使状态栏和导航栏变得透明
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initWindow();
}
@TargetApi(19)
private void initWindow(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
或者对主题设置(注意对 values 资源的限定,仅用于 API19 及以上): <item name="android:windowTranslucentNavigation">true</item> <item name="android:windowTranslucentStatus">true</item>
在使用沉浸式主题是,布局会往上移,如图
Flyme4.2 Android4.4.4上运行效果
这个问题也很好解决,有2个解决方案
1.在 style theme 添加
<item name="android:fitsSystemWindows">true</item> 有bug,布局中的Padding会失效
布局时是否考虑给系统窗口留出空间,true为留出空间(如 Status Bar and App bar)
2.计算状态栏的高度,为每个RootView设置Padding (推荐使用这个方法,因为fitsSystemWindows会产生比较多的问题,如Toast弹出位置也会往上移,最外层Padding也会失效)
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
之后我们再运行,却又发现,状态栏的位置出来了,但是。。。
实际上,状态栏已经透明了,只是状态栏底下没有颜色呀!
Google 了之后在 Github 找到了一个开源项目 SystemBarTint ,代码就变成下面这个样子:
private SystemBarTintManager tintManager;
@TargetApi(19)
private void initWindow(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintColor(getColor(R.color.app_main_color));
tintManager.setStatusBarTintEnabled(true);
}
}
运行之后,发现运行效果跟第一张图一样,达到我们想要的效果了。
跟踪进去查看 SystemBarTint 的源代码,会发现 SystemBarTintManager 的构造方法里面除了获取 ActionBar 的高度等等这些配置之外,还有一个重要的方法 setupStatusBarView
@TargetApi(19)
public SystemBarTintManager(Activity activity) {
Window win = activity.getWindow();
ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//省去部分代码...
if (mStatusBarAvailable) {
setupStatusBarView(activity, decorViewGroup);
}
if (mNavBarAvailable) {
setupNavBarView(activity, decorViewGroup);
}
}
于是接着查看 setupStatusBarView 的代码
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);
}
可以发现这个开源项目能够解决我们的问题的原因在这,就是往 DecorView 加入一个 View, 而在代码中我们将这个 View 的背景设置成 ActionBar 一样的颜色,所以就达到了沉浸式的效果。到这里,基本也就分析完成了。
附上源代码地址: Github 源代码 .
沉浸式状态栏的一个BUG, 导致在软键盘弹出后页面没有resize,内容被键盘遮住,adjustPan不起作用,如写说说、写日志这些界面。直接在需要relayout的子view上添加fitsSystemWindows属性。
部分rom(如miui和Flyme等)修改了状态栏高度,miui改高了,而meizu上的flyme则改矮了,所以不能直接写作25dp。在CustomTitleBar组件中通过重写getPaddingTop方法来兼容所有状态栏高度。
大部分应用了沉浸式状态栏的应用都没有考虑到这点,如腾讯地图,导致在那些rom上打开应用后状态栏一片白乎乎的看不清。
尽管google的原生4.4 rom中,在设置了沉浸式状态栏后,会对状态栏区域加上一条渐变的背景,来防止亮色导致状态栏图标/字看不清,但实际应用中发现其实很多rom把渐变阴影给去了,所以在状态栏组件中,加上了绘制阴影的选项(包括5.0半透明黑条和4.4渐变阴影两种选项),会在4.4机器开启了沉浸式状态栏时,绘制阴影。
小米 的MIUI6解决方案 : MIUI 6 沉浸式状态栏调用方法
- 不要设置Activity的theme的fitsSystemWindows为true
- 或者使用getApplicationContext()
相关链接:
http://www.jianshu.com/p/f8374d6267ef
http://blog.csdn.net/marktheone/article/details/46663035
http://codersimple.github.io/android/2015/05/15/immersive-theme-for-android.html
点击下载我的Demo源码
下面了解各种状态栏的定义
---------------------------------------------------------------------------------------------------
透明状态栏示例: