最近做项目的时候,遇到了这个问题,给自己做个笔记。
有时候我们需要某些背景或者自己定义的actionBar,由于状态栏的原因,会显得很突兀,不好看,所以我们需要对状态栏做一些处理
这个需要Android4.4以上的
如果我们不做处理,是这个样子的:
感觉很丑,不好看
我们先看一个基础的概念:
首先,我们先隐藏状态栏
加入下面这段代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
}
效果:
但是这种情况,只要我们下拉就可以显示状态栏,但是不会再恢复到之前
在具体实现之前,我们先看看API里面各种Flag的解释:
SYSTEM_UI_FLAG_FULLSCREEN
:
View has requested to go into the normal fullscreen mode so that its content can take over the screen while still allowing the user to interact with the application.
View要求全屏模式,所以内容会占据整个屏幕,直到用户对application做出反应SYSTEM_UI_FLAG_HIDE_NAVIGATION
:
View has requested that the system navigation be temporarily hidden.
View要求系统导航暂时被隐藏SYSTEM_UI_FLAG_IMMERSIVE
:
View would like to remain interactive when hiding the navigation bar with SYSTEM_UI_FLAG_HIDE_NAVIGATION.
当设置了SYSTEM_UI_FLAG_HIDE_NAVIGATION的时候同时设置这个,上拉View,导航栏会显示SYSTEM_UI_FLAG_IMMERSIVE_STICKY
:
View would like to remain interactive when hiding the status bar with SYSTEM_UI_FLAG_FULLSCREEN and/or hiding the navigation bar with SYSTEM_UI_FLAG_HIDE_NAVIGATION.
这个和上面的区别是,上面一旦显示了状态栏或者导航栏,就不能恢复全屏,而这个可以SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
:
View would like its window to be laid out as if it has requested SYSTEM_UI_FLAG_FULLSCREEN, even if it currently hasn’t.
这个似乎是View让window就像被要求全屏一样,但是并没有全屏
(我试了试,状态栏依然看得见)SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
:
View would like its window to be laid out as if it has requested SYSTEM_UI_FLAG_HIDE_NAVIGATION, even if it currently hasn’t.SYSTEM_UI_FLAG_LAYOUT_STABLE
:
When using other layout flags, we would like a stable view of the content insets given to fitSystemWindows(Rect).
当使用layout有关的flag的时候,对fitSystemWindows(Rect)提供的布局提供稳定
当我将UI的flag改为这个的时候:
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
然后在布局中的ImagView中:
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/bg_1"
android:scaleType="centerCrop"
android:fitsSystemWindows="true"
/>
得到的效果:
如果在ImageView的根布局设置android:fitsSystemWindows="true"
得到的是:
如果我将 android:fitsSystemWindows=”false”或者就不设置它,得到的就是含有状态栏和导航栏的全屏
SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
:
Requests the status bar to draw in a mode that is compatible with light status bar backgrounds.
这个API要求在23以上SYSTEM_UI_FLAG_LOW_PROFILE
:
View has requested the system UI to enter an unobtrusive “low profile” mode
就是隐藏状态栏上的一些东西,只剩下电池和时间SYSTEM_UI_FLAG_VISIBLE
:
View has requested the system UI (status bar) to be visible (the default).
默认的,都可见SYSTEM_UI_LAYOUT_FLAGS
:
Flags that can impact the layout in relation to system UI.
可以影响到系统UI的布局的标志
透明状态栏
我们来看代码:
if(Build.VERSION.SDK_INT >= 21){
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
getWindow().setStatusBarColor(Color.TRANSPARENT);
getWindow().setNavigationBarColor(Color.TRANSPARENT);
}
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
这个需要API 21以上的,所以我们需要加个判断
效果:
感觉上美多了
这样我们就更能理解前面的那两个flag了,它是让主体内容占据全屏,但是我们任然能看到状态栏和导航栏,但是如果将状态栏和导航栏的颜色变为透明,我们就能看到全部的主体内容了
真正的沉浸式:
if(Build.VERSION.SDK_INT >= 19){
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|View.SYSTEM_UI_FLAG_FULLSCREEN
|View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
效果:
我们看到上面我们对状态栏和导航栏设置透明是直接用的:getWindow().setStatusBarColor(Color.TRANSPARENT);
getWindow().setNavigationBarColor(Color.TRANSPARENT);
这是是API 21以上才能用,也就是支持Android5.0以上,因此我们要兼容4.4怎么办呢:
我们会使用到Window中的setFlags()方法:
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
这里,我使用的是toolbar
效果:
这个用的模拟器是android4.4,API 19的
如果我用android5.0 API 21
我们可以看到4.4的状态栏是透明的,而5.0的状态栏是半透明的
记得在toolbar中加一个android:fitsSystemWindows="true"
它的作用是什么呢:
官方描述:Boolean internal attribute to adjust view layout based on system windows such as the status bar. If true, adjusts the padding of this view to leave space for the system windows. Will only take effect if this view is in a non-embedded activity.
简单描述:
这个一个boolean值的内部属性,让view可以根据系统窗口(如status bar)来调整自己的布局,如果值为true,就会调整view的paingding属性来给system windows留出空间
实际效果:
当status bar为透明或半透明时(4.4以上),系统会设置view的paddingTop值为一个适合的值(status bar的高度)让view的内容不被上拉到状态栏,当在不占据status bar的情况下(4.4以下)会设置paddingTop值为0(因为没有占据status bar所以不用留出空间)。
如果我想4.4和5.0兼容,我是这样做的:
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|View.SYSTEM_UI_FLAG_LAYOUT_STABLE
);
window.setStatusBarColor(Color.TRANSPARENT);
window.setNavigationBarColor(Color.TRANSPARENT);
}else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
,WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
这样状态栏就不会半透明了
注意一点,合理使用fitSystemWindows