前言:

工作几年下来,处理statusbar的机会和场景不算多,每次遇到具体业务问题时,都是去网上找一些api解决当前问题,但是从来没有从根本上去了解statusbar的发展历程,今天下定决心去彻底认识statusbar。

了解statusbar的发展需要分三个阶段:

  1. Android4.4(API19 KitKat)以前:无法做任何事,是的,就是一坨黑色。
  2. Android4.4~Android5.0(API21 Lollipop):可以实现状态栏的变色,但是效果还不是很好,主要实现方式是通过FLAG_TRANSLUCENT_STATUS这个属性设置状态栏为透明并且为全屏模式,然后通过添加一个与StatusBar 一样大小的View,将View 设置为我们想要的颜色,从而来实现状态栏变色。
  3. Android5.0~Android6.0(API23 Marshmallow): 系统才真正的支持状态栏变色,系统加入了一个重要的属性和方法 android:statusBarColor (对应方法为 setStatusBarColor),通过这个属性可以直接设置状态栏的颜色
  4. Android6.0以后:主要就是添加了一个功能可以修改状态栏上内容和图标的颜色(黑色和白色)

下面开始了解主要的API:
一、首先新建一个项目,注意把values/values-v19/values-v21中凡是在style.xml中 有关 windowTranslucentNavigation、windowTranslucentStatus、statusBarColor 都删掉。 同时把布局带有android:fitsSystemWindows注释掉。

public class Main3Activity extends AppCompatActivity{@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main3);}}<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".Main3Activity"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="20dp"android:textColor="@android:color/holo_red_light"android:text="测试文案"/><Viewandroid:id="@+id/testview"android:layout_width="300dp"android:layout_height="300dp"android:background="@color/colorPrimary"tools:ignore="MissingConstraints" />
</LinearLayout>

跑出来的效果是:
从左到右分别是 API 19(4.4), 21(5.0), 29(9.+)

二、代码中设置FLAG_TRANSLUCENT_STATUS后,请看如下效果:

public class Main3Activity extends AppCompatActivity{@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main3);getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);}
}

4.4会全透明,页面上顶。
模拟器4.4应该是有bug,看不出效果,建议使用真机

4.4以上是一样的效果,页面整体上顶,沉在状态栏之下,同时状态栏变为透明!
下图左边是 api21, 右边是api29, 以下相同

这里我们给出一个结论:
android4.4—android5.0主要通过FLAG_TRANSLUCENT_STATUS这个属性实现状态栏变色,当使用这个flag时SYSTEM_UI_FLAG_LAYOUT_STABLE和SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN会被自动添加。

这显然不是我们想要的效果,我们试着让状态栏透明,同时页面不被状态栏遮挡
三、我们使用setFitsSystemWindows(android:fitsSystemWindows=“true”)这个api试试。

public class Main3Activity extends AppCompatActivity{@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main3);getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);ViewGroup rootView = (ViewGroup) ((ViewGroup) findViewById(android.R.id.content)).getChildAt(0);rootView.setFitsSystemWindows(true);}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:fitsSystemWindows="true"    //注意是这里!tools:context=".Main3Activity"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="20dp"android:textColor="@android:color/holo_red_light"android:text="测试文案"/><Viewandroid:id="@+id/testview"android:layout_width="300dp"android:layout_height="300dp"android:background="@color/colorPrimary"tools:ignore="MissingConstraints" />
</LinearLayout>
或者在XML局部中设置:


四、4.4没有提供改变statusbar颜色的方案,我们采取了一个hack的方式。
方法是:要添加一个view填充在状态栏上,view的高度就是状态栏的高度,颜色就是你想要的状态栏的颜色。

public class Main3Activity extends AppCompatActivity{private static final int FAKE_STATUS_BAR_VIEW_ID = R.id.statusbarutil_fake_status_bar_view;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main3);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);ViewGroup decorView = (ViewGroup) getWindow().getDecorView();View fakeStatusBarView = decorView.findViewById(R.id.statusbarutil_fake_status_bar_view);if (fakeStatusBarView != null) {if (fakeStatusBarView.getVisibility() == View.GONE) {fakeStatusBarView.setVisibility(View.VISIBLE);}fakeStatusBarView.setBackgroundColor(getResources().getColor(R.color.colorAccent));} else {decorView.addView(createStatusBarView(getResources().getColor(R.color.colorAccent)));}setRootView();}}private void setRootView() {ViewGroup parent = (ViewGroup) findViewById(android.R.id.content);for (int i = 0, count = parent.getChildCount(); i < count; i++) {View childView = parent.getChildAt(i);if (childView instanceof ViewGroup) {childView.setFitsSystemWindows(true);((ViewGroup) childView).setClipToPadding(true);}}}private View createStatusBarView( @ColorInt int color) {// 绘制一个和状态栏一样高的矩形View statusBarView = new View(this);LinearLayout.LayoutParams params =new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight());statusBarView.setLayoutParams(params);statusBarView.setBackgroundColor(color);statusBarView.setId(FAKE_STATUS_BAR_VIEW_ID);return statusBarView;}private int getStatusBarHeight() {// 获得状态栏高度int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");return getResources().getDimensionPixelSize(resourceId);}
}


注意:以下分析的api都与4.4无关了,4.4能做的事情就是对添加到顶部的view进行UI的变化,自主定制,思路都是一致的。

五、5.0(包含5.0)以上,设置statusbar的颜色可以直接利用一个window提供的api即可,不需要做任何限制。
注意:写改代码时一定要判断sdk版本,不加判断的话,运行到5.0以下机器上会直接crash

public class Main3Activity extends AppCompatActivity{@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main3);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);// 上面三行代码,如果设置为全透明,则必须加上,设置为半透明,则可以不需要getWindow().setStatusBarColor(getResources().getColor(R.color.colorAccent));}}
}

六、如果实现导航栏半透明,图片作为布局底部,沉在导航栏下的效果。

public class Main3Activity extends AppCompatActivity{@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main3);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {// 设置状态栏透明getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);}}
}<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".Main3Activity"><ImageViewandroid:layout_width="match_parent"android:layout_height="300dp"android:src="@drawable/brand_pic_kr"android:scaleType="centerCrop"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="20dp"android:textColor="@android:color/holo_red_light"android:text="测试文案"/><Viewandroid:id="@+id/testview"android:layout_width="300dp"android:layout_height="300dp"android:background="@color/colorPrimary"tools:ignore="MissingConstraints" />
</LinearLayout>

七、改变状态栏文字颜色:
Android 6.0 以上使用系统方法修改状态栏字体、图标颜色;
Android 4.4 到 6.0 之间使用第三方系统提供的方法修改状态栏字体、图标颜色(目前只有 MIUI 和 Flyme)。

  setMIUIStatusBarDarkIcon(activity, true);setMeizuStatusBarDarkIcon(activity, true);
//设置为黑色if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR |    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
//设置为白色
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}/*** 修改 MIUI V6  以上状态栏颜色*/private static void setMIUIStatusBarDarkIcon(@NonNull Activity activity, boolean darkIcon) {Class<? extends Window> clazz = activity.getWindow().getClass();try {Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");int darkModeFlag = field.getInt(layoutParams);Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);extraFlagField.invoke(activity.getWindow(), darkIcon ? darkModeFlag : 0, darkModeFlag);} catch (Exception e) {//e.printStackTrace();}}/*** 修改魅族状态栏字体颜色 Flyme 4.0*/private static void setMeizuStatusBarDarkIcon(@NonNull Activity activity, boolean darkIcon) {try {WindowManager.LayoutParams lp = activity.getWindow().getAttributes();Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");darkFlag.setAccessible(true);meizuFlags.setAccessible(true);int bit = darkFlag.getInt(null);int value = meizuFlags.getInt(lp);if (darkIcon) {value |= bit;} else {value &= ~bit;}meizuFlags.setInt(lp, value);activity.getWindow().setAttributes(lp);} catch (Exception e) {//e.printStackTrace();}}

API29状态栏文字设置为黑色的效果:

八、FLAG_FULLSCREEN的作用:

public class Main3Activity extends AppCompatActivity{@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main3);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);}}
}

分别为api19,21,29

使状态栏消失,比如小说阅读APP中可以使用到。

不得不提一句,除此以外,还有很多个flag,其实很多api功能重叠,或者因为版本问题遗留,导致该问题的处理上没有统一方案,大家找到适合自己的就好。

九、实现类似横屏视频播放的效果,默认不展示状态栏,触摸屏幕时显示出来状态栏。
参考:https://blog.csdn.net/sbsujjbcy/article/details/48391863

十、基本原理弄清楚以后,其实我们在实际使用中,可以推荐一个牛逼的轮子:
https://jaeger.itscoder.com/android/2016/03/27/statusbar-util.html

【Android基础】StatusBar重新认识相关推荐

  1. android 状态栏(StatusBar)

    一.SystemUI 概述 自 android2.2 开始 , 原本存在与 framework-res.apk 中的状态栏和下拉通知栏界面控制被分割出一个单独的 apk文件 , 命名为 SystemU ...

  2. Android基础新手教程——1.5.2 Git之使用GitHub搭建远程仓库

    Android基础新手教程--1.5.2 Git之使用GitHub搭建远程仓库 标签(空格分隔): Android基础新手教程 本节引言: 在上一节中.我们学习了怎样使用Git.构建我们的本地仓库.轻 ...

  3. android intent 源码,Android 基础之 IntentService 源码

    Android 基础之 IntentService 源码 Android,IntentService,源码 IntentService 位于 android.app 包下面,是 Service 的一个 ...

  4. 【Android基础】动画

    Android里的动画分为两类,以3.0版本为分水岭. 3.0前已存在 帧动画 补间动画 3.0出现 属性动画 帧动画 顾名思义,快速切换几张图片来达到动画的效果. 建立帧动画xml Note:不要把 ...

  5. 基于Android移动终端的微型餐饮管理系统的设计与实现4——Android基础

    本章将介绍一些在开发中用到的一些常用且值得介绍的Android 基础知识和技术,包括Fragment.Slidingmenu.RecyelerView.HelloCharts框架和Ormlite框架. ...

  6. 关于android基础教程一书的初步解读后发现的一些问题

    我是一个比较固执的人..在进行android基础教程一书的初步学习之后,说实话,这本书虽然说为了照顾有需要的童鞋,提供了所有的源代码,就连我也在亲自打了好久的代码之后最后决定放弃,也偷偷懒,进行简单无 ...

  7. Android基础总结+SQlite数据库【申明:来源于网络】

    Android基础总结+SQlite数据库[申明:来源于网络] 基础总结篇之一:Activity生命周期:http://blog.csdn.net/liuhe688/article/details/6 ...

  8. Android基础教程pdf

    下载地址:网盘下载 内容简介  · · · · · · <Android基础教程>内容完整丰富,具有较强的通用性,读者都能通过<Android基础教程>快速学习Android开 ...

  9. Android基础_数据存储

    2019独角兽企业重金招聘Python工程师标准>>> Android基础_数据存储 Android数据存储的几种形式 继承SQLiteOpenHelper public class ...

  10. android各目录大小,Android 基础篇 — 放不同drawable文件夹中图片的大小

    我们接着上篇文章Android 基础篇 - 不同DPI取哪个本地文件夹中的资源 讲,文末尾提到一个问题,为什么不同drawable文件夹中的图片大小在终端设备会不一样? 1 准备 在drawable- ...

最新文章

  1. mysql日期函数 简书_ios怎样搭建php服务器
  2. 积木赛尔号机器人_赛尔号11年,圣灵谱尼从章鱼变花臂少年,最终成为了老父亲...
  3. 变态题大串烧:微软面试问题 -- 三.难题:这类题有一定难度,如果得不到答案,也不能说明什么...
  4. windows2003权限如何配置
  5. Redis:常见的面试题
  6. python决策树生成规则_如何从scikit-learn决策树中提取决策规则?
  7. JZOJ 1322. 硬币游戏
  8. boost::process::cmd相关的测试程序
  9. 怎么看mysql有没有安装成功_MySQL 安装看这一篇就够了
  10. freebsd 手工安装zabbix2.0 php,zabbix 服务端,子客户端安装配置日志
  11. HashMap的底层原理
  12. Tips--更改Jupyter Notebook的默认工作路径
  13. java sort 效率_性能对比:collections.sort vs treeSet sort vs java8 stream.sorted
  14. Vue中如何实现代码高亮功能?
  15. linux pandas教程_Python Anaconda教程–了解最受欢迎的数据科学平台
  16. Jetpack—LiveData组件的缺陷以及应对策略 转至元数据结尾
  17. android dts播放器下载,安卓dts音效apk安装包
  18. mysql通过视图插入数据_数据库视图 sql
  19. java 标签的制作
  20. 先有鸡还是先有鸡蛋?C语言发展史给出的答案

热门文章

  1. 像素位移_PixelLogic像素画教程:高级像素位移
  2. JS逆向之Webpack 处理2
  3. 百立特(木瓜贴片:18927470109,专精3、5、10片SMT研发首件打样)
  4. OSPF不规则区域,LSA以及序列号
  5. Zotero PDF translate翻译CNKI报错
  6. 系统对接之以中间表形式对接,使用SpringBoot整合多数据源
  7. 817自动控制原理-1-开环传递函数与闭环传递函数
  8. 绥化计算机学校地址,绥化市职业技术教育中心学校
  9. epoll的底层实现原理
  10. 关系数据理论-数据库习题