前言

前段时间,突然收到一个状态栏颜色优化设计的任务,将原本应用整体的黑色状态栏修改为根据标题栏颜色进行沉浸式设计,显示效果如下:

 
image

经过分析及踩过N多坑,终于完成了APP全局的修改。现将一些需要注意的问题及踩过的坑进行梳理总结,主要从系统版本区别、各大厂商的ROM区别及具体的设置进行分析,期间也参考了很多资料,会在文末附上对应的链接

Android各版本状态栏区别

首先我们需要注意,Android不是各个版本都支持设置状态栏的颜色,只有在5.0以上才支持。另外6.0以上才支持设置状态栏黑色图标(避免白色状态栏及白色图标导致看不清电量 时间等问题)

 
image
系统版本 是否支持设置状态栏颜色 是否允许设置状态栏黑色图标
4.4
5.0
6.0+

各个ROM状态栏区别

是不是设置了状态栏透明就真透明了?

这个问题一开始也困扰了我,后面分析,在原生的系统虽然设置了状态栏透明,但是状态栏区域也会有一层半透明的遮罩(估计就是考虑到白色状态栏引起的问题),但是测试发现部分国产ROM设置穿透栏透明则会完全透明(例如MIUI)

原生系统效果如下:

 
image

MIUI系统效果如下:

 
image

是不是6.0都支持系统状态栏黑条图标?

原生6.0以上有API支持,但是国产各ROM经过定制,有的需要特定的设置才能实现

原生系统设置:

  public void setLightStatusBar(Window window, boolean lightStatusBar) {
// 设置浅色状态栏时的界面显示
View decor = window.getDecorView();
int ui = decor.getSystemUiVisibility();
if (lightStatusBar) {
ui |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} else {
ui &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
decor.setSystemUiVisibility(ui); }
小米: public static boolean MIUISetStatusBarLightMode(Window window, boolean dark) {
boolean result = false;
if (window != null) {
Class clazz = window.getClass();
try {
int darkModeFlag = ;
Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
if (dark) {
extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
} else {
extraFlagField.invoke(window, , darkModeFlag);//清除黑色字体
}
result = true;
} catch (Exception e) { }
}
return result;
}

魅族:

public static boolean FlymeSetStatusBarLightMode(Window window, boolean dark) {
boolean result = false;
if (window != null) {
try {
WindowManager.LayoutParams lp = window.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 (dark) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(lp, value);
window.setAttributes(lp);
result = true;
} catch (Exception e) { }
}
return result;
}

华为手机:
部分测试发现华为的EMUI手机状态栏会跟系统桌面的状态栏一样,设置了没用,这里如果要特殊设置状态栏颜色,只能参考4.4的处理方式(后续介绍)

 
image

如何进行定制状态栏

原理分析

  • 4.4

通过上述的版本及分析,可见完善的的状态栏兼容是一个大工程,需要综合考虑系统版本及各个厂商ROM等因素。5.0以上有系统API进行支持,这里我们主要来分析一些4.4的实现原理。
简单来说,4.4的实现方式就是使用透明的状态栏,然后做一个和状态栏一样高度的View,加入到Windows的DecorView,然后给这个View设置背景色,达到实现状态栏颜色。

 window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

        ViewGroup decorViewGroup = (ViewGroup) window.getDecorView();
View statusBarView = decorViewGroup.findViewWithTag(STATUS_BAR_VIEW_TAG);
if (statusBarView == null) {
statusBarView = new StatusBarView(window.getContext());
statusBarView.setTag(STATUS_BAR_VIEW_TAG);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.TOP;
statusBarView.setLayoutParams(params);
decorViewGroup.addView(statusBarView);
}
statusBarView.setBackgroundColor(color);
StatusBarCompat.internalSetFitsSystemWindows(window, true);
 
image
  • 5.0

注意5.0一般不用使用白色的状态栏(因为不能设置状态栏灰色图标),可在资源文件定义一个rgb,区分版本,5.0使用白灰色

 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void setStatusBarColor(Window window, int color) {
//取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//设置状态栏颜色
window.setStatusBarColor(color);
}
 
image
  • 6.0
 @TargetApi(Build.VERSION_CODES.M)
@Override
public void setStatusBarColor(Window window, int color) {
//取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//设置状态栏颜色
window.setStatusBarColor(color); // 去掉系统状态栏下的windowContentOverlay
View v = window.findViewById(android.R.id.content);
if (v != null) {
v.setForeground(null);
}
}
 
image

实现方案

这里不重复造轮子,先提供一下github上比较完善的处理方案

status-bar-compat

StatusBarCompat是一个用于设置系统状态栏颜色的兼容库,兼容Android 4.4.2(API 19)以上,使用简单,仅需要一行代码的调用。

SystemBarTint

支持4.4以上的,主要使用透明状态栏的方式实现

推荐使用status-bar-compat,已考虑到整体的版本兼容机及各厂ROM,调用简单。

在Activity的setContentView()方法调用之后,调用以下方法即可。
 StatusBarCompat.setStatusBarColor(this, color, lightStatusBar);
或者是 StatusBarCompat.setStatusBarColor(this, color);

本文主要源码使用status-bar-compat中的代码进行说明

关于全屏及非全屏界面切换导致页面移动问题

例如在应用中有全屏的看图页面,点击返回为非全屏(带状态栏)页面,非全屏页面由于现实状态,会出现页面抖动。目前暂无完善的处理方案,项目中暂时使用的方式是延迟全屏页面的finish,先显示状态栏后再关闭

复写onBackPressed
getActivity().getWindow().clearFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN);
if(getView()!=null){
getView().postDelayed(new Runnable() {
@Override
public void run() {
getActivity().finish();
}
},);
}

状态栏一片白色

上面已有分析,要注意如果状态栏为白色,需要设置状态栏的图标颜色。status-bar-compat中会把颜色转换成灰度值,然后自己控制状态栏图标颜色

 public static void setStatusBarColor(Activity activity, @ColorInt int color) {
boolean isLightColor = toGrey(color) > ;
setStatusBarColor(activity, color, isLightColor);
} /**
* 把颜色转换成灰度值。
* 代码来自 Flyme 示例代码
*/
public static int toGrey(@ColorInt int color) {
int blue = Color.blue(color);
int green = Color.green(color);
int red = Color.red(color);
return (red * + green * + blue * ) >> ;
}

部分第三方组件的弹层和白色状态栏显得比较突兀

 
image

这个目前也尚无方法,考虑可以在弹层出现时,动态修改状态的颜色,但是工作量比较大,可先适当调整弹层的rgb,减低透明度

参考资料

Android 6.0 以上实现状态栏白底黑字

status-bar-compat

作者:黄俊彬
链接:https://www.jianshu.com/p/ace8f7921cde
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

玩转Android状态栏的更多相关文章

  1. 玩转Android之数据库框架greenDAO3.0使用指南

    用过ActiveAndroid.玩过ORMLite,穿过千山万水,最终还是发现greenDAO好用,ActiveAndroid我之前有一篇文章介绍过 玩转Android之数据库框架ActiveAndr ...

  2. Android状态栏颜色修改

    android状态栏颜色修改   状态栏颜色的修改在4.4和5.x环境下分别有不同的方式,低于4.4以下是不能修改的.   5.x环境下 方式一,状态栏将显示为纯净的颜色,没有渐变效果 /** * 状 ...

  3. Android状态栏透明(沉浸式效果)

    Android状态栏透明(沉浸式效果) 默认效果 沉浸式效果 方式一 源码 下载地址(Android Studio工程):http://download.csdn.net/detail/q487880 ...

  4. Android状态栏着色

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 状态栏着色,也就是我们经常听到的沉浸式状态栏,关于沉浸式的称呼网上也有很多吐槽的,这里就不做过多讨论了,以下我们统称状态栏着色,这样 ...

  5. android状态栏和NavigationBar的动态控制显示

    项目在开发阅读器,阅读器对阅读界面的要求就是在工具栏不显示的状态下,ActionBar和NavigationBar都是不显示的,当工具栏显示时它们都出来,这就需要动态控制它们的显示与隐藏. 第一阶段: ...

  6. [Android] 状态栏的一些认识

    前段时间遇到几个关于状态栏的问题,又了解了一下状态栏相关的知识,现在做一下记录. 本文地址:http://www.cnblogs.com/rossoneri/p/4316343.html 前戏和问题 ...

  7. 利用FFmpeg玩转Android视频录制与压缩(二)<转>

    转载出处:http://blog.csdn.net/mabeijianxi/article/details/72983362 预热 时光荏苒,光阴如梭,离上一次吹牛逼已经过去了两三个月,身边很多人的女 ...

  8. Android状态栏微技巧,带你真正意义上的沉浸式

    记得之前有朋友在留言里让我写一篇关于沉浸式状态栏的文章,正巧我确实有这个打算,那么本篇就给大家带来一次沉浸式状态栏的微技巧讲解. 其实说到沉浸式状态栏这个名字我也是感到很无奈,真不知道这种叫法是谁先发 ...

  9. Android状态栏微技巧,带你真正理解沉浸式模式【转】

    感谢! 本文转自大佬郭霖:http://blog.csdn.net/guolin_blog/article/details/51763825 转载请注明出处:http://blog.csdn.net/ ...

随机推荐

  1. C++入门经典-例4.8-同名的全局变量和局部变量

    1:代码如下: // 4.8.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> using ...

  2. SecureCRT For Mac安装、破解、使用详细总结

    转:https://blog.csdn.net/so_geili/article/details/83315852#_4 https://www.sednax.com/download.php

  3. layer实现关闭弹出层刷新父界面功能详解

    本文实例讲述了layer实现关闭弹出层刷新父界面功能.分享给大家供大家参考,具体如下: layer是一款近年来备受青睐的web弹层组件,她具备全方位的解决方案,致力于服务各水平段的开发人员,您的页面会 ...

  4. 手动清空微信PC客户端数据

    微信PC客户端,用久了之后,会产生大量数据,包括聊天记录.聊天图片.视频等等,非常占存储空间,除非很重要的聊天记录或文件,建议额外保存,其他的可以手动删掉就好,可以节省存储空间. 1.找到[C:\Us ...

  5. IFB上挂载NETEM

    转发虚拟网卡的ingress 建立虚拟网卡的ingress转发到ifb0(每一个Pod): tc qdisc add dev calixxxxxxxxxxx ingress tc filter add ...

  6. Report List 报表开发

    1. Report List的输出定义 * ...NO STANDARD PAGE HEADING: 输出的报表不包含表头: * ...LINE-SIZE col : 输出的报表不包含表头: * .. ...

  7. UniEAP Platform V5.0 Unable to compile class for JSP

    流程设计器报错: http://127.0.0.1:8080/framework/workflow/webdesign/procmodify/procmodifydetail.jsp?isLoadDa ...

  8. java:多线程(代理模式,Thread中的方法,Timer,生产者和消费者)

    *进程:一个正在运行的程序,进程是操作系统分配资源的基本单位,每个进行有独立的内存空间,进程之间切换开销较大. *线程:一个轻量级的进程,线程是任务调度的基本单位,一个进程可以有多个线程, * 系统没 ...

  9. GoLand远程Linux开发环境搭建

    Goland 远程调试本文介绍如何从本机的goland连接远端server上的go代码进行调试 goland下载安装 建议购买正版,科学使用自行搜索. 需要安装插件,确保可以访问官网,不然配置下pro ...

  10. 磁盘的分区和挂载(mount)

    一.挂载问题的引入 我们大多数人用惯了windos系统,对linux系统中磁盘的管理就先入为主,不太好理解挂载这一动作.在linux系统中添加一块新磁盘后,要进行分区.格式化(分配文件系统).挂载.当 ...