方法一:通过设置Theme主题设置状态栏透明
因为 API21 之后(也就是 android 5.0 之后)的状态栏,会默认覆盖一层半透明遮罩。且为了保持4.4以前系统正常使用,故需要三份 style 文件,即默认的values(不设置状态栏透明)、values-v19、values-v21(解决半透明遮罩问题)。
values styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style>
values-v19
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!--values-v19。v19 开始有 android:windowTranslucentStatus 这个属性-->
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
</resources>
values-v21
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">true</item>
<!--Android 5.x开始需要把颜色设置透明,否则会呈现系统默认的浅灰色-->
<!--android 5.0开始有android:statusBarColor这个设置-->
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
样式主题沉浸主要是针对4.4以上也就是version>=19的,如果是小于19的话,用values里面的样式主题
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
这就类似以前老版本我们隐藏titleBar(ActionBar),在代码中设置,在setContentView()之前添加
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);//继承AppCompatActivity使用requestWindowFeature(Window.FEATURE_NO_TITLE);//继承Activity使用
但是这两种方法针对4.4以下只是隐藏了actionBar我们还要隐藏到statusBar,4.4以下版本隐藏statusBar参考博文
但是有时候我们有需求需要将状态栏的高度空出来,有可能布局文字和状态栏的字体重叠了,这里介绍三种方法
1.设置fitsSystemWindow属性
一般就是在布局的最外层设置android:fitsSystemWindow = "true"属性.当然也可以代码设置:
/**
* 设置页面最外层布局 FitsSystemWindows 属性
* @param activity
* @param value
*/
public static void setFitsSystemWindows(Activity activity, boolean value) {
ViewGroup contentFrameLayout = (ViewGroup) activity.findViewById(android.R.id.content);
View parentView = contentFrameLayout.getChildAt(0);
if (parentView != null && Build.VERSION.SDK_INT >= 14) {
parentView.setFitsSystemWindows(value);
}
}
通过该设置保留状态栏高度的 paddingTop
后,再设置状态栏的颜色。就可以达到设想的效果。但这种方式实现有些问题,例如我们想设置状态栏为蓝色,只能通过设置最外层布局的背景为蓝色来实现,然而一旦设置后,整个布局就都变成了蓝色,只能在下方的布局内容里另外再设置白色背景,而这样就存在过度绘制了。而且设置了 fitsSystemWindows=true
属性的页面,在点击 EditText 调出 软键盘时,整个视图都会被顶上去。
所谓System windows指的就是屏幕上status bar 、 navigation bar等系统控件所占据的部分。而android:fitsSystemWindows="true"就是通过设置View的padding,使得应用的content部分(Activity中setContentView()中传入的content)不会与system window重叠。
所以说,我们的第一种场景,需要content 和 status bar重叠,自然就不能传入true。而第二种场景,需要content与status bar不重叠,也就需要设置fitSystemwindows为true。
2.布局文件里面添加占位栏
① 在跟布局文件添加状态栏,这样虽然整个内容页面时顶到头的,但是因为在内容布局里添加了一个占位状态栏,所以效果与设想的一致。
<View
android:id="@+id/statusBarView"
android:background="@color/blue"
android:layout_width="match_parent"
android:layout_height="wrap_content"></View>
通过反射获取系统状态栏高度:
public int getStatusBarHeight() {
int result = 0;
int resourceId = activity.getApplication().getResources().getIdentifier("status_bar_height", "dimen",
"android");
if (resourceId > 0) {
result = activity.getApplication().getResources().getDimensionPixelSize(resourceId);
}
return result;
}
设置占位图高度:
View statusBar = findViewById(R.id.statusBarView);
ViewGroup.LayoutParams layoutParams = statusBar.getLayoutParams();
layoutParams.height = getStatusBarHeight();
② 当然,除了从布局文件中添加这一方式之外,一样可以在代码中添加。比较推荐使用代码添加的方式,方便封装使用。
/**
* 用代码向contentview添加状态栏占位图
* @param activity
* @param color
*/
private 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());
statusBarView.setBackgroundColor(color);
contentView.addView(statusBarView, lp);
}
3.代码中添加paddingTop并添加到占位状态栏
手动给根视图设置一个 paddingTop
,高度为状态栏高度,相当于手动实现了fitsSystemWindows=true
的效果,然后再在根视图加入一个占位视图,其高度也设置为状态栏高度。
public void addStatusViewBySettingPaddingTop(Activity activity, int color){
//设置 paddingTop
ViewGroup rootView = (ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content);
rootView.setPadding(0,getStatusBarHeight(),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());
statusBarView.setBackgroundColor(color);
decorView.addView(statusBarView, lp);
}
}
个人认为最优解应该是第三种方法,通过这种方法达到沉浸式的效果后面也可以很方便地拓展出渐变色的状态栏。
方法二:在代码中设置
通过在代码中设置,实现方法一中在 Theme 主题样式里设置的属性,便于封装。
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 = getWindow();
WindowManager.LayoutParams attributes = window.getAttributes();
attributes.flags |= flagTranslucentNavigation;
window.setAttributes(attributes);
getWindow().setStatusBarColor(Color.TRANSPARENT);
} else {
Window window = 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
*/
private void fullScreen(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);
} } }