关于 Android 中的各类 Bar 和“透明状态栏”的一些知识

此篇文章主要讲解关于沉浸式状态栏,程序全屏和分清状态栏、ActionBar、ToolBar 的一些知识内容。主要是讲解如何适配状态栏。关于 ActionBar 和 ToolBar 的使用没有细致讲解。java

文章最先发布于个人微信公众号 Android开发者家园
本文为sydMobile原创文章,能够随意转载,但请务必注明出处! 因为我的精力有限,多个渠道发布,排版可能会有问题。重点维护个人我的公众号「 Android 开发者家园 」android

其实这篇主要是讲解适配状态栏的,在这其中可能有些读者对状态栏(StatusBar)、ActionBar、ToolBar、TitleBar有点混淆或者感受很混乱,因此就有了这其中的内容。bash

关于 TitleBar、ActionBar、ToolBar、StatusBar

首先强调一点 StatusBar 和前面这几种 Bar 是彻底的两回事,其实 statusbar 应该写成 status bar ,也就是咱们的状态栏。没错就表示咱们 Android 中最上面显示时间、通知的那一栏。微信

提及 TitlBar、ActionBar、ToolBar,要和 Android 的发展历史有关了。网络

在 Android 3.0 以前,设计上没有美感之说,知识为了完成功能,这个时候最上面样式就是显示当前页面的 Title,也就是 TitleBar,这个时代的 Android 机都是有物理返回键的。这个时候就是充当一个 Title 的做用,这也就是 TitleBar。它的样子是这样的ide

titlebar.png

上面显示MyStudyDemo 的一栏就是 TitleBar 了。布局

而后在 Android 3.0 API 11 开始注重美感了,引进了 HOLO 样式,这个时候用 ActionBar代替了 TitleBar 了。这个时候的 Bar 的功能再也不仅仅限于展现标题了,有了不少的新功能。字体

actionbar.png

Fragment 也是在 Android 3.0 的时候引入的,因此 Android 3.0 对于 Android 的发展史仍是很重要的。ui

最简单的 ActionBarspa

简单ActionBar.png

值得注意的是 TitleBar 和 ActionBar 在本质上是同样的,他们都不是咱们经常使用的控件的形式,而是绑定在 DecorView 中的,能够经过 getWindow().setFeatureInt() 暴露出的几个方法进行修改功能和样式。

正是由于 ActionBar 是嵌套在 DecorView 中的,它不是一个独立的控件,并且因为国内的 Android 应用开发环境,通常都不遵循 Google 的那一套设计,因此运用起来很不灵活。随后在 Android 5.0 推出了 ToolBar 控件,这是一个彻底独立的控件,你能够尽情的运用了。

2019-04-25_20-44-48.png

好了,到这里来应该完全分清楚这几个 bar 了吧,这是 Android 的一个历史发展造成的,能够结合个人这篇文章 blog.csdn.net/sydMobile/a… 来详细的看一下 Android 在样式上的发展。

状态栏的历史以及更正错误叫法

由于上面也说了 ActionBar 是在 Android 3.0 之后才引用的,可是真正的规范是在 Android 4.1 以及以上。因此在 Android 4.1 如下版本是不支持 ActionBar 的。这里针对 ActionBar 的操做全是在 Android 4.1 以上运行的,不适用于 Android 4.1 如下版本。

说明:在 Android 4.4 以前状态栏一直就是黑色的,在 Android 4.4 中带来了 windowTranslucentStatus 这一特性,这个时候才能够给状态栏设置颜色。在国内将这种状态栏变色叫作沉浸式状态栏,其实这种叫法是错误的,可是时间久了,你们都这么叫了,就不追究了,就把这种状态栏变色叫作沉浸式状态栏了(这也是由国内互联网发展太过迅速,忽略了不少细节点,相关方面的人才缺少,另外一个方面是国内的 Android 开发环境形成的,碎片化太过严重,不一样的手机厂商关于这些又有不一样的叫法)。

关于沉浸式和透明式概念说明

在谷歌官方中:

在 Android 4.4 Google 引入了能够在阅读电子书、玩游戏、看电影时支持全屏模式(Immersive Mode 沉浸模式),同时也支持更改修改状态栏的颜色。

能够知道在官方是根本没有 沉浸式状态栏 这种说法的。只有 沉浸模式 就是其实就是出于全屏状态。所谓的 ”沉浸式状态栏“,相似于下面图的样子:

透明状态栏.png

上面也说了这种错误的叫法是不对的,没有沉浸式状态栏 ,这种样式只是将内容 UI 设置成了全屏,把状态栏设置成了透明。因此这种是叫作 状态栏透明模式

设置透明状态栏

先来几组效果图,从效果 1 开始逐渐递进演示,这里面的几个重要参数会在后面具体说明,这里先说明现象

1.内容布局全屏

在 Android 4.1 以上设置去除状态栏或者认为是状态栏被内容布局遮挡了(全屏)和去除 ActionBar

View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(option);
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
// 状况说明:采用这种方式全屏,若是你切换到别的应用程序,或者在通知栏下拉一下,状态栏就会下来,咱们的 UI 布局就会跑到状态栏下面,和没有设置的时候效果是同样的。
复制代码

效果图:

screen.png

2.内容布局全屏(被状态栏遮住顶部)
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
// 能够看到咱们在 option 中添加了一个 STABLE 属性,这个属性是用阿里保持咱们的 UI 视图稳定的,使得它不会由于系统 UI 的变化而从新 layout 。记住这个属性长和 FLAG_LAYOUT_XXX 这种属性在一块儿使用。STABLE 就是会始终给系统 UI 保留一个空间(无论系统 UI 有没有消失,而且悬浮在咱们本身的 UI 视图上面 )
// 能够看到这种效果,状态栏仍然还在,只是你仔细发现,原布局有一部分被状态栏给覆盖了,也就是说这种方式的话,布局延伸到了状态栏。这个时候咱们只要设置状态栏为透明。就是咱们想要的透明状态栏的那种效果了。
复制代码

效果图:

layout_fullscreen.png

3.由效果 2 变成透明状态栏模式
// 只须要在 2 的基础上把状态栏设置成透明就能够了
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
if(Build.VERSION.SDK_INT >= 21){
    // 这个方法只有 5.0 后才能够用,也就是说 Android 5.0 之前不支持更改状态栏颜色,这是说的是原生系统
    // 小米的 ui 在 Android 5.0 以前也提供了修改方法
    getWindow.setStatusBarColor(Color.TRANSPARENT);
}
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
// 这样咱们的状态栏就变成透明的了,就是人们常说的“沉浸式状态栏”
复制代码

layout_fullscreen_tran.png

4.属性 STABLE 的做用
// 主要是为了验证 STABLE 的做用,在 1 的案例中,咱们只用 FLAG_FULLSCREEN 属性,会发如今切换应用或者触碰系统 UI 的时候,这个时候咱们的状态栏就会出来,而后咱们的 UI 布局就会“被压在”状态栏的下面(其实是把咱们的布局从新 layout 了)而后若是添加 STABLE 属性呢?
if (Build.VERSION.SDK_INT >= 21){
    View decorView = getWindow().getDecorView();
    int option = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
    decorView.setSystemUiVisibility(option);
    getWindow().setStatusBarColor(Color.TRANSPARENT);
}
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
// 结果就是 提早预留了一块系统 UI 的控件,下拉的时候,状态栏内容就会显示出来。(这样咱们的 UI 布局是没有被从新 layout 的)

复制代码

screnn_stable.png

5.沉浸模式
// 所谓沉浸模式就是一开始咱们的 UI 布局是全屏的,状态栏和虚拟导航键也是隐藏的,当咱们须要的系统 UI 的时候,从状态栏的位置下拉就能够出现系统 UI,这个时候就须要一个新的属性了 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 须要在 Android 4.4 及其以上版本
	@Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus && Build.VERSION.SDK_INT >=19){
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility( 
                     View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            );

        }
    }
// 当触摸底部或者上部状态栏的时候,导航栏和状态栏就会出来,过一会就会消失,相似于游戏中那样。
复制代码

immersive_sticky_all.png

最后,总结这几个 FLAG 的做用
  • View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN:做用就是使咱们的 UI 布局能够延伸到状态栏,状态栏悬浮会遮挡住咱们的 UI 布局,和 View.SYSTEM_UI_FLAG_LAYOUT_STABLE 一块儿使用
  • View.SYSTEM_UI_FLAG_FULLSCREEN:做用使 UI 布局延伸到状态栏,全屏显示,状态栏消失,下拉的时候,状态栏依然会出现,而且再也不消失。
  • View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY:沉浸模式,配合 View.SYSTEM_UI_FLAG_FULLSCREEN 和 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 来实现
  • View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION :做用就是使咱们的 UI 布局能够延伸到导航栏,导航栏悬浮会遮挡住咱们的 UI 布局。
  • View.SYSTEM_UI_FLAG_HIDE_NAVIGATION:做用使 UI 布局延伸到导航栏,全屏显示,导航栏消失。单独使用的话,触碰 UI 任何地方,系统都会将这个属性设置去除,再也不生效所以须要和 View.SYSTEM_UI_FLAG_IMMERSIVE 配合使用
  • View.SYSTEM_UI_FLAG_IMMERSIVE:单独使用是没有任何意义的,须要和 View.SYSTEM_UI_FLAG_FULLSCREEN、View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 配合使用,当出现隐藏的系统栏的时候,以前的全部设置就会被清除。

修改状态栏颜色

Android 5.0 (API 21) 后支持直接修改状态栏的颜色,在 Android 4.4(API 19)以前是不容许操做状态栏的,也就是说在 Android 4.4 以前,咱们是无法对状态栏进行任何操做的。

Android 4.4 修改状态栏颜色
// 将状态栏设置为透明(须要 API 19) 设置成这种模式后,状态栏会变成透明,咱们的内容布局(只是咱们 Activity 对应的布局,不包含 Window 中的 ActionBar)会占据系统栏。相似于 getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | LAYOUT_STABLE); getWindow().setStatusBarColor(Color.TRANSPARENT);

// 首先设置状态栏为透明
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

// 这个时候,咱们的布局内容中占据系统栏了,这个时候,咱们只须要本身来建立一个系统栏背景就能够了。
View mStatusBarView = new View(context);
int screenWidth = 屏幕宽度;
int statusBarHeight = 状态栏高度(是能够获取的);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(screenWidth,statusBarHeight);
mStatusBarView.setLayoutParams(params);
mStatusBarView.requestLayout();
// 获取系统默认的根布局
ViewGroup systemContent = findViewById(android.R.id.content);
// 这个就是咱们本身的布局文件
ViewGroup userContent = systemContent.getChildAt(0);
// 添加到咱们的布局中
userContent.addView(mStatusBarView,0);

复制代码
Android 5.0 修改状态栏颜色
// 方法一  
getWindow().setStatusBarColor(int color );
// 方法二
样式中: <item name="colorPrimaryDark">@color/colorAccent</item> 对应状态栏颜色
复制代码

修改状态栏文字颜色

关于状态栏的文字颜色,是在 Android 6.0 才开始能够支持修改的

// 修改为 黑色字体
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);

复制代码

setFitsSystemWindows

setFitsSystemWindows(boolean is);
在直接调用这个方法的时候,只有咱们本身的根布局(在 mContentParentParent 中,titleBar 的位置是固定的),调用才起做用。表示是否保留系统栏的空间。能够在布局属性中设置。做用和给控件添加 "fitsSystemWindows" 属性相同。
若是设置了这个属性为 true,那么则是保留系统 UI 的位置(其实是固定了咱们的 UI 的高度,咱们 UI 的高度就是屏幕去掉系统栏高度后的高度),那么这个时候你如何设置了 FLAG_LAYOUT_HIDE_NAVIGATION 是不起做用的,由于咱们的布局高度已经肯定了,不可能延伸到系统栏。
复制代码

设置布局彻底全屏的方式:

// 方式一
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 方式二
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
// 方式三 style.xml 中配置
<style name = "fullScreen" parent="Theme">
	<item name="android.windowFullscreen">true</item>
</style>

// 总结:
关于 addFlags 和改变 statusbar 颜色的方法在 getWindow 里面
复制代码

页面布局

为了说明页面的布局关系,这里引入一张图片(来自网上)

Android页面来自网络.png

每一个 Activity 对应一个页面,是不包括 status bar 的,不过可设置 status bar 显示仍是不显示,能够设置 Activity 是否延伸到 status bar 的位置(确切的来讲是 Window 窗口)

DecorView 是继承自 FrameLayout 的。

其中 mContentParent 的 id 是 com.android.internal.R.id.content

mContentParent 经过这个 id 就能够获取到咱们本身的布局的根布局了。

titleBar 也有一个 id

相关文章:yifeng.studio/2017/02/19/…

更多资源请查看我的公众号

欢迎你们关注个人微信公众号,和我交流分享
相关文章
相关标签/搜索