自己在使用手机的过程中都会看到其他app的透明状态栏(或者国内成为沉浸式状态栏),再看看自己app上放系统通知栏黑黑的一块,突兀又不和谐,就想着把自己的app也弄得比较炫一些。
言归正传,下面记录下操作步骤和可能有坑的点,欢迎指正~
1. 5.0系统以上
2. BaseActivity中加入
Window window = getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//先将状态栏调整为透明
window.setStatusBarColor(Color.TRANSPARENT);
是不是看到那么多的FLAG_XXX
心都累了,这些累人的FLAG_XXX
我们先按下不表,我们直接来看下最后一行。
各位看官可能要说了,最后一行那么简单,不就是设置个状态栏颜色呗,整段代码可能就这行看得最清晰了。
嗯,单纯从代码的角度,这行是最清晰不过的了,但是前面的这些累人的FLAG_XXX
可都跟这行的代码有着密切的关系。让我们直接进入这个方法中查看下
/**
* Sets the color of the status bar to {@code color}.
*
* For this to take effect,
* the window must be drawing the system bar backgrounds with
* {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and
* {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS} must not be set.
*
* If {@code color} is not opaque, consider setting
* {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
* {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
* <p>
* The transitionName for the view background will be "android:status:background".
* </p>
*/
public abstract void setStatusBarColor(@ColorInt int color);
仔细把注释看完,是不是就明白那些FLAG_XXX
到底是为什么需要那样设置了。
简单来说,这个setStatusBarColor(@ColorInt int color)
方法要求我们的window
- 必须没有
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
这是第二行代码window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
的由来 - 必须有
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
这则是第四行代码window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
的由来。
然后,当你需要的是非透明颜色的状态栏时,需要设置两个标志
分别是View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
与View.SYSTEM_UI_FLAG_LAYOUT_STABLE
,这样就搞清楚了代码第三行所做的工作
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
3. 根据app的主色调去调整状态栏的颜色(对于有actionBar之类的界面)
有眼尖的小伙伴们应该已经发现我们之前的代码上设置状态栏的颜色是透明,这没有达到我们需要的效果啊,我们需要的是跟app主色调相同的那个颜色,我当然也知道这点,可是为什么要先设置成透明的呢,这是因为考虑到有些界面我们会设置为全屏,不显示系统通知栏,这时就要区分这两种情况了。再根据自己的需求来设置颜色。
如果没有这方面的需求,直接在上一步设置需要的颜色就可以了。
4. fitsSystemWindows方法
其实到第三步做完,我们已经能看到通知栏变成了我们所想要的颜色,效果如下图
看起来已经搞定了啊,还需要做些什么呢。那是因为我们的ContentView中只有一个TextView,所以并不能很清楚地展示效果是如何,接下来,改造下ContentView再来观察下效果
这次应该比较直观能看到问题所在了,我们的ContentView的区域被系统通知栏遮住了一块。
这需要我们在每个页面的根布局中加入以下这句话
android:fitsSystemWindows="true"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical">
不过每个页面加这个很麻烦,也可以全局的style中加入
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:fitsSystemWindows">true</item>
</style>
这时再来看下效果
已经没有遮挡了,这时才算真的大功告成。
5. 坑
效果达成了,难免会遇到一些坑,下面我记录下我遇到的几个问题点
- 有些界面需要全屏展示
上文说到的第三步,其实在实际运用中我是去判断是否有自定义的ActionBar存在,有则使用app主色调,没有则是第一步中的Transparent,所以在没有自定义ActionBar的界面会变成灰色的状态栏,解决方案是在这些特殊的界面全屏,我的做法是使用theme来达到全屏的效果
android:theme="@android:style/Theme.Light.NoTitleBar"
- Toast显示不正常问题
这个应该是Toast也被fitsSystemWindows限制的问题,解决方法是我们showToast的时候传入的是个系统上下文
context ------------> context.getApplicationContext()
- 自定义View显示不正常问题
如一部分view缺失等问题,这时需要把自定义view在代码或者xml中设置android:fitsSystemWindows="false"
setFitsSystemWindows(false);
或者
//第7行
<me.roadley.ui.VerticalTextView
android:id="@+id/some_tv"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/some_color"
android:fitsSystemWindows="false"
app:text="@string/some_string"
app:textColor="@color/white"
app:textSize="14sp"
android:layout_centerVertical="true"/>
后记
5.0开始,Google推出Material Design,使用Theme.Material(MD主题)或Theme.AppCompat主题并至少设置ColorPrimaryDark属性就可以实现status bar半透明效果。
不过我们的项目并没有使用AppCompat主题,而且个人觉得与自己的ActionBar相同的颜色这种感觉会比较好哈~