【Android基础】StatusBar重新认识
前言:
工作几年下来,处理statusbar的机会和场景不算多,每次遇到具体业务问题时,都是去网上找一些api解决当前问题,但是从来没有从根本上去了解statusbar的发展历程,今天下定决心去彻底认识statusbar。
了解statusbar的发展需要分三个阶段:
- Android4.4(API19 KitKat)以前:无法做任何事,是的,就是一坨黑色。
- Android4.4~Android5.0(API21 Lollipop):可以实现状态栏的变色,但是效果还不是很好,主要实现方式是通过FLAG_TRANSLUCENT_STATUS这个属性设置状态栏为透明并且为全屏模式,然后通过添加一个与StatusBar 一样大小的View,将View 设置为我们想要的颜色,从而来实现状态栏变色。
- Android5.0~Android6.0(API23 Marshmallow): 系统才真正的支持状态栏变色,系统加入了一个重要的属性和方法 android:statusBarColor (对应方法为 setStatusBarColor),通过这个属性可以直接设置状态栏的颜色
- 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重新认识相关推荐
- android 状态栏(StatusBar)
一.SystemUI 概述 自 android2.2 开始 , 原本存在与 framework-res.apk 中的状态栏和下拉通知栏界面控制被分割出一个单独的 apk文件 , 命名为 SystemU ...
- Android基础新手教程——1.5.2 Git之使用GitHub搭建远程仓库
Android基础新手教程--1.5.2 Git之使用GitHub搭建远程仓库 标签(空格分隔): Android基础新手教程 本节引言: 在上一节中.我们学习了怎样使用Git.构建我们的本地仓库.轻 ...
- android intent 源码,Android 基础之 IntentService 源码
Android 基础之 IntentService 源码 Android,IntentService,源码 IntentService 位于 android.app 包下面,是 Service 的一个 ...
- 【Android基础】动画
Android里的动画分为两类,以3.0版本为分水岭. 3.0前已存在 帧动画 补间动画 3.0出现 属性动画 帧动画 顾名思义,快速切换几张图片来达到动画的效果. 建立帧动画xml Note:不要把 ...
- 基于Android移动终端的微型餐饮管理系统的设计与实现4——Android基础
本章将介绍一些在开发中用到的一些常用且值得介绍的Android 基础知识和技术,包括Fragment.Slidingmenu.RecyelerView.HelloCharts框架和Ormlite框架. ...
- 关于android基础教程一书的初步解读后发现的一些问题
我是一个比较固执的人..在进行android基础教程一书的初步学习之后,说实话,这本书虽然说为了照顾有需要的童鞋,提供了所有的源代码,就连我也在亲自打了好久的代码之后最后决定放弃,也偷偷懒,进行简单无 ...
- Android基础总结+SQlite数据库【申明:来源于网络】
Android基础总结+SQlite数据库[申明:来源于网络] 基础总结篇之一:Activity生命周期:http://blog.csdn.net/liuhe688/article/details/6 ...
- Android基础教程pdf
下载地址:网盘下载 内容简介 · · · · · · <Android基础教程>内容完整丰富,具有较强的通用性,读者都能通过<Android基础教程>快速学习Android开 ...
- Android基础_数据存储
2019独角兽企业重金招聘Python工程师标准>>> Android基础_数据存储 Android数据存储的几种形式 继承SQLiteOpenHelper public class ...
- android各目录大小,Android 基础篇 — 放不同drawable文件夹中图片的大小
我们接着上篇文章Android 基础篇 - 不同DPI取哪个本地文件夹中的资源 讲,文末尾提到一个问题,为什么不同drawable文件夹中的图片大小在终端设备会不一样? 1 准备 在drawable- ...
最新文章
- mysql日期函数 简书_ios怎样搭建php服务器
- 积木赛尔号机器人_赛尔号11年,圣灵谱尼从章鱼变花臂少年,最终成为了老父亲...
- 变态题大串烧:微软面试问题 -- 三.难题:这类题有一定难度,如果得不到答案,也不能说明什么...
- windows2003权限如何配置
- Redis:常见的面试题
- python决策树生成规则_如何从scikit-learn决策树中提取决策规则?
- JZOJ 1322. 硬币游戏
- boost::process::cmd相关的测试程序
- 怎么看mysql有没有安装成功_MySQL 安装看这一篇就够了
- freebsd 手工安装zabbix2.0 php,zabbix 服务端,子客户端安装配置日志
- HashMap的底层原理
- Tips--更改Jupyter Notebook的默认工作路径
- java sort 效率_性能对比:collections.sort vs treeSet sort vs java8 stream.sorted
- Vue中如何实现代码高亮功能?
- linux pandas教程_Python Anaconda教程–了解最受欢迎的数据科学平台
- Jetpack—LiveData组件的缺陷以及应对策略 转至元数据结尾
- android dts播放器下载,安卓dts音效apk安装包
- mysql通过视图插入数据_数据库视图 sql
- java 标签的制作
- 先有鸡还是先有鸡蛋?C语言发展史给出的答案