沉浸式状态栏就是大家常见的把某张图片放到了状态栏上,其实从安卓4.4之后我们就可以更改状态栏的颜色了,不过4.4到5.0之间的设备操作方式比5.0之后要复杂一点,让我们一步一步实现操作吧。
我们可以通过代码来实现:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
window.setNavigationBarColor(Color.TRANSPARENT);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//4.4到5.0
WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();
localLayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
}
缺点:
所以我们的界面会向上偏移一个状态栏的高度,一般首页上方是Banner,图片UI可以给调整,但是其他界面就会出现问题,比如你的Toolbar就可能被状态栏遮挡,一般我处理这种问题就是上方加一个25dp高度的View,颜色和Toolbar保持一致。
有个属性叫fitsSystemWindows 得属性,在activity的整体布局中使用,设置为true之后就可以自动的处理虚拟按键、状态栏和我们界面的关系,但是无法做到沉浸,状态栏会变成灰色,我们的页面不能沉到他的下面去,而是并在一起。
说一说我在项目中的使用吧,由于我的项目只有HomeFragment(首页)的Banner要沉浸在状态栏下方,所以我给MainActivity单独设置了一个Theme,但是MainActivity中又只有HomeFragment含有此banner,对于其他的Fragment我单独添加的view来适配。
1.values-v19包中和values-v21包中都对状态栏设置成透明,虚拟按键不设置成透明,如果你设置成透明的,在华为和Nexus系列的手机上会遮挡布局。
2.V-19包中MainActivity的fitsSystemWindows设置为false,其他的页面此属性设置为true这样他就不会被整个页面操控从而空出状态栏了,因为我们想要修改4.4到5.0之间手机的状态栏颜色,必须要先把状态栏给搞没,然后才能做下一步操作
V-21包中fitsSystemWindows属性都要设置为false,因为5.0之后我们就可以自定义状态栏颜色了,其实这个属性是相对与状态栏来使用的,如果我的状态栏设置为透明,此属性设置为true之后,状态栏变成灰色,否则就沉到状态栏下面,我们的MainActivity设置了状态栏透明,而且就是要沉到状态栏下方,所以此属性就设置成false;
v-19:
<style name="AppTheme" parent="Theme.Design.NoActionBar">
<!-- 虚拟按键不透明 -->
<item name="android:windowTranslucentNavigation">false</item>
<!-- 透明状态栏 -->
<item name="android:windowTranslucentStatus">true</item>
<!-- 界面不沉浸到状态栏下方 -->
<item name="android:fitsSystemWindows">true</item>
<style name="MainTheme" parent="AppTheme">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:fitsSystemWindows">false</item>
</style>
然后是v-21,因为5.0之后的可以自定义状态栏颜色,所以其他页面不需要让状态栏透明:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:fitsSystemWindows">false</item>
<!-- Actionbar color toolbar-->
<item name="colorPrimary">@color/colorPrimary</item>
<!-- Status bar color 顶部状态栏 -->
<item name="colorPrimaryDark">@color/colorPrimary</item>
<style name="MainTheme" parent="AppTheme">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">false</item>
</style>
3.恶心的地方就是4.4到5.0这些个版本,我们已经把项目中的所有非MainActivity的页面的状态栏给变灰了,其实就是空出了状态栏的高度,那个地方现在时空的,为此,我在顶层封装的BaseActivity中,判断了当前的手机版本,如果是该区间的手机版本,就构建出一个对应高度的view填充到状态栏,这样4.4之后的手机状态栏的颜色都是可控的了
public void setContentView(int layoutResID) {
super.setContentView(layoutResID);
StatusBarCompat.compat(this, getResources().getColor(R.color.colorPrimary));
其中StatusBarCompat是从鸿洋那搬过来的,稍加了改动,就是剔除了不需要添加view的界面,附在下面。对于MainActivity中,由于我们的一个Fragment需要沉到状态栏下面,所以除了需要沉下去的,其他Fragment我在布局中都给他们添加了一个25dp的view。
这就是我的方式了,虽然这样做有点牵强,但是我纠结很多天之后最终还是选择了这种方式,暂时还没有找到更好的解决方式,希望以后能解决。
public class StatusBarCompat {
private static final int INVALID_VAL = -1;
private static final int COLOR_DEFAULT = Color.parseColor("#f94548");
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static void compat(Activity activity, int statusColor)
{
//剔除引导页、启动页、主界面
Class cls =activity.getClass();
if(cls.equals(MainActivity.class)||cls.equals(WelcomeActivity.class)||cls.equals(IntroduceActivity.class)){
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
{
int color = COLOR_DEFAULT;
ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
contentView.setFitsSystemWindows(true);
if (statusColor != INVALID_VAL)
{
color = statusColor;
}
View statusBarView = new View(activity);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
getStatusBarHeight(activity));
statusBarView.setBackgroundColor(color);
contentView.addView(statusBarView, lp);
}
}
public static void compat(Activity activity)
{
compat(activity, INVALID_VAL);
}
public static int getStatusBarHeight(Context context)
{
int result = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
{
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
}