本文介绍的修改状态颜色的方法仅支持android4.4及以上系统,操作大致分为2个步骤:
1.将状态栏透明化
2.覆盖透明的状态栏
效果图:
状态栏透明化
可通过代码设置,一般写在BaseActivity中,例如:
//5.0及以上
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
/*
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_FULLSCREEN |View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
getWindow().setStatusBarColor(Color.TRANSPARENT);
*/
//上面代码发现在华为mate10的android8.1手机上无效,状态栏是全白的,因此修改成下面
Window window = getWindow();
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.setStatusBarColor(Color.TRANSPARENT);
}
//4.4到5.0
else if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){
WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();
localLayoutParams.flags = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS |
localLayoutParams.flags;
}
也可以通过样式设置,需要在 values、values-v19、values-v21 目录下分别创建相应的主题
values/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Base application theme. -->
<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>
<style name="TranslucentTheme" parent="AppTheme"></style>
</resources>
values-v19/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TranslucentTheme" parent="AppTheme">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">false</item>
</style>
</resources>
values-v21/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TranslucentTheme" parent="AppTheme">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
然后在清单文件中设置对应的Activity或者Application的主题为:
android:theme="@style/TranslucentTheme"
提示:将状态栏透明化后,直接运行项目会发现界面布局直接延伸到状态栏,透过状态栏可以看到布局界面.
注意:Android7.0上按照上面的设置后,状态栏会变灰,解决办法如下:
在setContentView方法前调用这段代码:
//解决Android7.0下沉浸式状态栏变灰的问题
private void initStatueBar() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
try {
Class decorViewClazz = Class.forName("com.android.internal.policy.DecorView");
Field field = decorViewClazz.getDeclaredField("mSemiTransparentStatusBarColor");
field.setAccessible(true);
field.setInt(getWindow().getDecorView(), Color.TRANSPARENT); //改为透明
} catch (Exception e) {}
}
}
覆盖状态栏
利用布局延伸到状态栏的特性,我们可以直接使用布局的背景颜色做为需要的状态栏颜色,只需要在根布局中设置一个paddingTop为状态栏的高度即可,这个paddingTo最好区分下4.4之前和之后的,因为如果4.4之前的话状态栏是没有透明化,也就不需要设置paddingTop了.解决思路就是创建多一个dimens.xml在values-v19目录下.
values/dimens.xml
<resources>
<dimen name="padding_top">0dp</dimen>
</resources>
values-v19/dimens.xml
<resources>
<dimen name="padding_top">25dp</dimen>
</resources>
paddingTop的值可以自行测量,接近状态栏的高度即可,也可以使用下面的代码获取状态栏的高度
private int getStatusBarHeight(Context context) {
int statusBarHeight = 0;
try {
Class c = Class.forName("com.android.internal.R$dimen");
Object obj = c.newInstance();
Field field = c.getField("status_bar_height");
int x1 = Integer.parseInt(field.get(obj).toString());
statusBarHeight = context.getResources().getDimensionPixelSize(x1);
} catch (Exception var7) {
var7.printStackTrace();
}
return statusBarHeight;
}
另一种方式,就是屏蔽掉布局延伸到状态栏的特性,然后添加一个和状态栏高/宽相同的指定颜色的View来覆盖透明化的状态栏.
如何屏蔽?
只需要在布局文件的根节点就中设置android:fitsSystemWindows="true"属性即可.
如何通过View覆盖状态栏?
其实Activity在onCreate方法中调用setContentView(resId)方法设置布局的时候,它是将该布局作为系统id为android.R.id.content容器的子节点,而该容器是一个FrameLayout,因此可以通过下面的方式获取该FrameLayout
ViewGroup contentView = (ViewGroup) findViewById(android.R.id.content);
拿到该容器后,就可以添加一个宽高和状态栏相同的View来覆盖状态栏了,具体代码如下:
public void addStatusBarView(int colorId) {
//创建指定颜色的View
View view = new View(this);
view.setBackgroundColor(getResources().getColor(colorId));
//设置View的宽高,高度为状态栏高度,获取的代码上面有提到
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
getStatusBarHeight(this));
//获取布局文件添加的父容器
ViewGroup contentView = (ViewGroup) findViewById(android.R.id.content);
//添加到容器中
contentView.addView(view, params);
}
最后补充下设置状态栏和导航栏相关的flag
View类提供了setSystemUiVisibility和getSystemUiVisibility方法,这两个方法实现对状态栏的动态显示或隐藏的操作,以及获取状态栏当前可见性。
setSystemUiVisibility(int visibility)方法可传入的实参为:
1. View.SYSTEM_UI_FLAG_VISIBLE:显示状态栏,Activity不全屏显示(恢复到有状态栏的正常情况)。
2. View.INVISIBLE:隐藏状态栏,同时Activity会伸展全屏显示。
3. View.SYSTEM_UI_FLAG_FULLSCREEN:Activity全屏显示,且状态栏被隐藏覆盖掉。
4. View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN:Activity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态遮住。
5. SYSTEM_UI_FLAG_LAYOUT_STABLE : 表示会让应用的主体内容占用系统状态栏的空间,必须和SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN配合使用.
6. View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION:效果同View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
7. View.SYSTEM_UI_LAYOUT_FLAGS:效果同View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
8. View.SYSTEM_UI_FLAG_HIDE_NAVIGATION:隐藏虚拟按键(导航栏)。有些手机会用虚拟按键来代替物理按键。
9. View.SYSTEM_UI_FLAG_LOW_PROFILE:状态栏显示处于低能显示状态(low profile模式),状态栏上一些图标显示会被隐藏。
如果想实现沉浸式模式,可以重写Activity的onWindowFocusChanged方法如下:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus && Build.VERSION.SDK_INT >= 19) {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);//状态栏粘性
}
}
这样就可以实现,界面默认情况下是全屏的,状态栏和导航栏都不会显示。而当我们需要用到状态栏或导航栏时,只需要在屏幕顶部向下拉,或者在屏幕底部向上拉,状态栏和导航栏就会显示出来
源码下载