Android透明状态栏与沉浸模式全解

Android透明状态栏与沉浸模式全解

现在如今利用状态栏做文章的主要就是如下四种场景了,先上图

  • 网易云音乐 状态栏与标题栏同色,无缝衔接
  • 多看阅读 全屏沉浸阅读(视频,游戏同理)
  • 淘宝 状态栏深色
  • 饿了么 图片延伸至状态栏下面

透明状态栏模式就是大家说的"沉浸式状态栏"了.

沉浸模式是一般用于小说、视频、游戏。将用户的注意完全聚焦在内容上,是真正的沉浸模式.

从3.x版本开始, 系统DecorView提供了setSystemUiVisibility方法, 可以通过设置Flag更改所谓SystemUI的属性,可以操作各种状态栏,导航栏的的显示与隐藏效果。非常好用,有篇很好的总结文章Android Activity 全屏方法总结
调用方式:

getWindow().getDecorView().setSystemUiVisibility(
    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
);

不同的标记用|连接,这里着重解释一下这几个标记

  • View.SYSTEM_UI_FLAG_LAYOUT_STABLE Level 16
    保持整个View稳定,使View不会因为SystemUI的变化而做layout,常跟statusbar 悬浮, 隐藏共用,若不设置的话,statusbar的的显示和隐藏则会导致ContentView重新计算大小并绘制,因此这个标记通常是必须的

  • View.SYSTEM_UI_FLAG_FULLSCREEN Level 16
    状态栏隐藏,完全不见了,就如同在看视频时,屏幕上没有任何内容之外的东西

  • View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN Level 16
    状态栏透明,悬浮在浮于Activity的上面,想像有个z轴,这时activity可以完全占用整个屏幕,而之前我们的屏幕还要分一些给statusbar

  • View.SYSTEM_UI_FLAG_HIDE_NAVIGATION Level 14
    隐藏导航栏, 性质如SYSTEM_UI_FLAG_FULLSCREEN

  • View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION Level 16
    导航栏上浮于Activity,性质如SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

1.首先看效果图(1)和(3),这两个的实现原理其实一样,就是状态栏着色的颜色不同,又两种实现思路

1.直接将状态栏的颜色设置为目标颜色
window.setStatusBarColor(int);

它只适用于5.0之后。因此直接设置statusBar颜色的方式在5.0以下不行

2.将状态栏设置为"透明+悬浮",这时我们的布局就可以延伸到状态栏下面了,然后在activity的布局里面制造一块和状态栏等尺寸的view,设置需要的背景颜色即可,因为状态栏是透明的,因此看起来就像是状态栏被上了色一样,效果相同。通过添加这个标记便可以实现我们需要的"透明+悬浮"效果,
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

顺变说下清除标记的方法
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

其实我们查看FLAG_TRANSLUCENT_STATUS的源码就会发现,它其实就是上面说的system UI visibility flags里面的稳定布局SYSTEM_UI_FLAG_LAYOUT_STABLE和悬浮status标记的组合

* <p>When this flag is enabled for a window, it automatically sets
* the system UI visibility flags {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and{@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.</p>
*/
public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;

这就很容易理解了,现在直接上全部代码

 /**
 * 思路:直接设置状态栏的颜色
 */
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setStatusBarUpperAPI21() {
    Window window = getWindow();
    //取消设置悬浮透明状态栏,ContentView便不会进入状态栏的下方了
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

    //设置状态栏颜色
    window.setStatusBarColor(getResources().getColor(R.color.bg_green));
}

/**
 * 思路:设置状态栏悬浮透明,然后制造一个和状态栏等尺寸的View设置好颜色填进去,就好像是状态栏着色了一样
 */
private void setStatusBarUpperAPI19() {
    Window window = getWindow();
    //设置悬浮透明状态栏
    window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

    ViewGroup mContentView = (ViewGroup) findViewById(Window.ID_ANDROID_CONTENT);
    int statusBarHeight = getStatusBarHeight();
    int statusColor = getResources().getColor(R.color.bg_green);

    View mTopView = mContentView.getChildAt(0);
    if (mTopView != null && mTopView.getLayoutParams() != null &&
            mTopView.getLayoutParams().height == statusBarHeight) {
        mTopView.setBackgroundColor(statusColor);
        return;
    }

    //制造一个和状态栏等尺寸的 View
    mTopView = new View(this);
    ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);
    mTopView.setBackgroundColor(statusColor);
    //将view添加到第一个位置
    mContentView.addView(mTopView, 0, lp);
}

private int getStatusBarHeight() {
    int result = 0;
    int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resId > 0) {
        result = getResources().getDimensionPixelSize(resId);
    }
    return result;
}

这里注意为什么还要区分5.0和4.4不同的方案来实现,因为WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS这个标记在6.0上不是全透明而是半透明的,那么如果要实现效果(1)网易云音乐那样的效果的话就不行了,所以在5.0以上的版本我们直接设置statusBar的颜色。5.0以下通过制造一个和statusbar等尺寸的view着色填进去。

最终的效果如下,让4.4也有了差不多的效果:


而效果(3)就是改了个深色的颜色就行了:


2.看效果图(4),这就是让图片延伸到状态栏下,和1一样的思路,用纯xml和纯代码均可实现

  • XML方式实现:
    xml方式就是通过为acitivity设置style的方式实现,因为不同的版本需要的配置不同,因我们为4.4和5.0建立values文件夹和styles文件,并在样式文件中建立相同名字的样式,这样系统就能判断手机版本自动使用对应版本values文件夹下的样式,如图所示,注意路径

values/styles.xml添加内容:
<style name="fullScreenTheme" parent="AppTheme">
</style>

values-v19/styles.xml添加内容:

    <style name="fullScreenTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowTranslucentStatus">true</item>
    <item name="android:windowTranslucentNavigation">true</item>
</style>

values-v21/styles.xml添加内容:

    <style name="fullScreenTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowTranslucentStatus">false</item>
    <item name="android:windowTranslucentNavigation">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
</style>

windowTranslucentStatus:设置透明悬浮状态栏,4.4就有
windowTranslucentNavigation:设置透明悬浮导航栏,4.4就有

注意既然windowTranslucentStatus在4.4就有了,为什么在5.0的style要设置windowTranslucentStatus为false并且呢,其实这个问题前面就说过了

window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

<item name="android:windowTranslucentStatus">true</item>
看出来了吗,对他们俩其实是一个东西,一个是xml实现,一个是代码实现
所以windowTranslucentStatus在6.0上的效果是半透明的。效果是这样的,

而我们的最终效果:


另外,如果加了DrawerLayout,打开是状态栏在5.0以上没有任何问题,但是在4.4就是是灰色的。需要添加两行代码做处理:

    mDrawerLayout.setFitsSystemWindows(true);
    mDrawerLayout.setClipToPadding(false);

setFitsSystemWindows方法的作用是是否为系统默认的装饰预留空间
setClipToPadding方法是使得绘制区域可以延伸到padding区域

其实这里用了这两个方法虽然有效,但是我也不知道为什么,有知道朋友请告诉我。

这样我们就完全使用代码完美解决了效果(4)。

  • 代码实现:
    主要就是setSystemUiVisibility的运用

    public void onShow() {
    //5.0以上手动设置statusBar为透明。不能使用getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    //因为这在4.4,5.0确实是全透明,但是在6.0是半透明!!!
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    getWindow().setStatusBarColor(Color.TRANSPARENT);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

          getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
      }
    
      getWindow().getDecorView().setSystemUiVisibility(
              View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                      | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                      | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
    
      );
    

    }

3.效果(2)全屏沉浸,如小说,视频,游戏

在看完setSystemUiVisibility的各种flag的左右后,应该可以凭自己的需要组合搭配flag来实现全屏了,直接上代码:

public void onHide() {


    //4.1及以上通用flags组合
    int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        getWindow().getDecorView().setSystemUiVisibility(
                flags | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
        );
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        getWindow().getDecorView().setSystemUiVisibility(flags);
    }
}

就这么几行代码,注意这个全屏是可以支持到4.1的

参考:
Android Activity 全屏方法总结
Android 系统状态栏沉浸式/透明化完整解决方案
Android 状态栏全透明策略
Android开发:Translucent System Bar 的最佳实践

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • 关于沉浸式状态栏一词的说法从何而来我们无从考证。但这确实是个错误的说法先引用官方的一段话。 Immersive f...
    ifjgm阅读 9,011评论 3 46
  • 前言在使用App的过程中,如果细心观察,我们会发现,某些应用顶部菜单栏颜色会延伸到系统状态栏中,使得菜单栏和状态栏...
    heyzhuyue阅读 756评论 0 1
  • 前言 原文:http://blog.csdn.net/mybeta/article/details/5076032...
    naturs阅读 23,081评论 8 70
  • 前言 这种效果从android4.4开始引进的,并且在5.0进行了改进。因此,也只能将这一特性应用在android...
    谷歌哥哥阅读 1,500评论 0 2
  • 前言 首先请大家看几张图: 以上的效果,一般我们统称为沉浸式状态栏。其实,这种叫法不是很准确,而且也没有沉浸式状态...
    宇是我阅读 3,799评论 2 28