Android沉浸式状态栏,看完这篇就够了!

article/2025/8/24 8:27:24

背景

之前做过Android沉浸式状态栏的相关需求,但是一直忙于工作,没时间系统的整理下沉浸式相关的知识,所以今天抽出时间,写一篇 Android沉浸式状态栏的文章。

何为沉浸式

沉浸式就是要给用户提供完全沉浸的体验,使用户有一种置身于虚拟世界之中的感觉。
沉浸式模式就是整个屏幕中显示都是应用的内容,没有状态栏也没有导航栏,用户不会被一些系统的界面元素所打扰。
Android沉浸式模式的本质就是全屏化,但这可能并不是我们想要的,我们还是来实现下网上传的沸沸扬扬的Android沉浸式状态栏

沉浸式状态栏的兼容情况

Android版本透明状态栏
<4.4×
4.4-5.0
>=5.0
Android版本黑白字符状态栏
<6.0×
>=6.0

fitsSystemWindows

在讲沉浸式状态栏之前,我们先来认识一个属性——fitsSystemWindows,这个属性在沉浸式状态中扮演着非常重要的角色。

  • 官方描述

Boolean internal attribute to adjust view layout based on system
windows such as the status bar. If true, adjusts the padding of this view to leave space for the system windows. Will only take effect if this view is in a non-embedded activity.

  • 中文描述

Boolean内部属性是基于系统窗口(如status bar)调整视图布局。如果为true,将调整视图padding为系统窗口预留出空间。Will only take effect if this view is in a non-embedded activity.
这句话的意思是view不在非嵌入式的activity才会生效。
嵌入式activity是托管在父activity中的活动。常见的例子是TabHost / TabActivity设计。特别是,嵌入式Acitvities位于主机中 LocalActivityManager,这在概念上类似于 FragmentManager 它允许您在另一个内部显示一个Activity。

根据这个定义,很容易理解为什么只有主机(非嵌入式)Activity才能支持 fitsSystemWindows 属性,因为任何嵌入的活动都限制在其主机定义的区域内。

  • 注意:

fitsSystemWindows只作用在sdk>=19的系统上就是高于4.4的系统,android:fitsSystemWindows默认值为false,并且在哪个控件设置android:fitsSystemWindows="true"会有不一样的效果

android:fitsSystemWindows=“true”,这个属性可以给任何view设置,只要设置了这个属性此view的所有padding属性失效.只有在设置了透明状态栏(StatusBar)或者导航栏(NavigationBar)此属性才会生效

当设置了透明状态栏(StatusBar)时:
当为此activity设置了

<item name="android:windowTranslucentStatus">true</item>
或者
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}

如果有以上两种情况之一,我们的状态栏(StatusBar)就会变成透明,并且布局会扩展到StatusBar的位置同时,所有设置了android:fitsSystemWindows="true"属性的view会自动添加一个值等于状态栏高度的paddingTop

当设置了透明导航栏(NavigationBar)时:
当为此activity设置了:

<item name="android:windowTranslucentNavigation">true</item>
或者
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}

如果有以上两种情况之一,我们的导航栏(NavigationBar)就会变成透明,并且布局会扩展到NavigationBar的位置。同时,所有设置了android:fitsSystemWindows="true"属性的view会自动添加一个值等于导航栏高度的paddingBottom。

沉浸式状态栏实现的一般思路

  • 4.4以下版本: 我们可以对StatusBar和 NavigationBar进行显示和隐藏操作,但无法实现沉浸式状态栏。

  • Android4.4(API 19) - Android 5.0(API 21): 通过FLAG_TRANSLUCENT_STATUS设置状态栏为透明并且为全屏模式,然后通过添加一个与StatusBar 一样大小的View,将View 的 background 设置为我们想要的颜色,从而来实现沉浸式。

  • Android 5.0(API 21)以上版本: 在Android 5.0的时候,加入了一个重要的属性和方法 android:statusBarColor (对应方法为 setStatusBarColor),通过这个方法我们就可以轻松实现沉浸式。也就是说,从Android5.0开始,系统才真正的支持沉浸式。

  • Android 6.0(API 23)以上版本: Android6.0以上的实现方式和Android 5.0 +是一样,但从Android 6.0(API 23)开始,我们可以改状态栏的绘制模式,可以显示白色或浅黑色的内容和图标(除了魅族手机,魅族自家有做源码更改,6.0以下就能实现)

Android4.4(API 19) - Android 5.0(API 21)实现沉浸式的方式

Android 4.4 为什么能够实现沉浸式的效果呢?因为在Android 4.4 新增了一个重要的属性:FLAG_TRANSLUCENT_STATUS

 /*** Window flag: request a translucent status bar with minimal system-provided* background protection.** <p>This flag can be controlled in your theme through the* {@link android.R.attr#windowTranslucentStatus} attribute; this attribute* is automatically set for you in the standard translucent decor themes* such as* {@link android.R.style#Theme_Holo_NoActionBar_TranslucentDecor},* {@link android.R.style#Theme_Holo_Light_NoActionBar_TranslucentDecor},* {@link android.R.style#Theme_DeviceDefault_NoActionBar_TranslucentDecor}, and* {@link android.R.style#Theme_DeviceDefault_Light_NoActionBar_TranslucentDecor}.</p>** <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;

解释:设置状态栏透明,并且变为全屏模式。上面的解释已经说得很清楚了,当window的这个属性有效的时候,会自动设置 system ui visibility的标志SYSTEM_UI_FLAG_LAYOUT_STABLE和SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN.

有两种方式实现这个属性:

可以在代码中设置,如下:

activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

当然也可以在theme 中设置属性windowTranslucentStatus,如下:

android:windowTranslucentStatus

效果如下:
Alt
效果如上图,可以看出,沉浸式的效果是出来了,但是也有一个问题,我们的标题栏和状态栏重叠了,相当于整个布局上移了StatusBar 的高度。为了让标题栏回到原来的位置,我们在标题栏的上方添加一个大小和StatusBar大小一样的View,View 的BackgroundColor 为标题栏一样的颜色,这个View起到一个占位的作用。这个时候,标题栏就会下移StatusBar的高度,回到正常的位置。
添加如下代码:

       //获取windowphone下的decorViewViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();int       count     = decorView.getChildCount();//判断是否已经添加了statusBarViewif (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) {decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha));} else {//新建一个和状态栏高宽的viewStatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha);decorView.addView(statusView);}ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);//rootview不会为状态栏留出状态栏空间ViewCompat.setFitsSystemWindows(rootView,true);rootView.setClipToPadding(true);

创建和status bar 一样大小的View的代码如下:

 private static StatusBarView createStatusBarView(Activity activity, int color, int alpha) {// 绘制一个和状态栏一样高的矩形StatusBarView statusBarView = new StatusBarView(activity);LinearLayout.LayoutParams params =new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));statusBarView.setLayoutParams(params);statusBarView.setBackgroundColor(calculateStatusColor(color, alpha));return statusBarView;}

其中StatusBarView 就是一个普通的View。
添加上述代码后,效果如下:
Alt
通过以上就可以实现Android 4.4 上的沉浸式状态栏

另外,如果是一张图片延伸到状态栏的话,直接设置FLAG_TRANSLUCENT_STATUS就可以了,如下:
Alt

小结:Android4.4上实现沉浸式状态栏的套路是:为window添加FLAG_TRANSLUCENT_STATUS Flag,然后添加一个和status bar 一样大小的View 站位,从而让让标题栏不会与status bar重叠。而图片延伸到状态栏只需要设置FLAG_TRANSLUCENT_STATUS就OK。

沉浸式在Android4.4 - Android5.0 之间的版本表现得不是很好,从上面贴的几张图就可以看出,状态栏的顶部有一个渐变,会显示出黑色的阴影(底部的导航栏也是一样的效果),在Android 5.0 版本已经被修复了。

Android 5.0(API 21)以上实现沉浸式的方式

Android 5.0 是一个里程碑式的版本,从Android 5.0开始,Google 推出了全新的设计规范 Material Design,并且原生控件就可以实现一些炫酷的UI动效。从这个版本开始,google 加入了一个比较重要的方法setStatusBarColor (对应属性:android:statusBarColor),通过这个方法,可以很轻松地实现沉浸式状态栏。方法如下:

 /*** Sets the color of the status bar to {@code color}.** For this to take effect,* the window must be drawing the system bar backgrounds with* {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and* {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS} must not be set.** If {@code color} is not opaque, consider setting* {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and* {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.* <p>* The transitionName for the view background will be "android:status:background".* </p>*/public abstract void setStatusBarColor(@ColorInt int color);

注意看这个方法的注释,想要这个方法生效,必须还要配合一个Flag一起使用,必须设置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS ,并且不能设置FLAG_TRANSLUCENT_STATUS(Android 4.4才用这个)
看一下FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS这个flag:
可以看到,这个flag 也是在Android 5.0添加的,它的作用是什么呢?

Alt

解释:设置了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,表明会Window负责系统bar的background 绘制,绘制透明背景的系统bar(状态栏和导航栏),然后用getStatusBarColor()和getNavigationBarColor()的颜色填充相应的区域。这就是Android 5.0 以上实现沉浸式导航栏的原理。

实现沉浸式添加如下代码:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//注意要清除 FLAG_TRANSLUCENT_STATUS flag
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(getResources().getColor(android.R.color.holo_red_light));

效果如下:
Alt

当然也可以直接在Theme中使用,在values-v21文件夹下添加如下主题:

<style name="MDTheme" parent="Theme.Design.Light.NoActionBar"><item name="android:windowTranslucentStatus">false</item><item name="android:windowDrawsSystemBarBackgrounds">true</item><item name="android:statusBarColor">@android:color/holo_red_light</item></style>

效果和上面代码中添加的效果一样。

图片延伸到状态栏

Android 5.0使图片延伸到状态栏,只需设置windowTranslucentStatus,将 statusBarColor 设置为透明即可:

<style name="ImageTranslucentTheme" parent="Theme.AppCompat.DayNight.NoActionBar"><item name="android:windowTranslucentNavigation">true</item><item name="android:windowTranslucentStatus">true</item><!-- 设置statusBarColor 为透明--><item name="android:statusBarColor">@android:color/transparent</item></style>

效果如下:
Alt

代码实现方式中通过版本号的判断兼容 Android5.0以下和Android 5.0以上:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha));} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();int count = decorView.getChildCount();if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) {decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha));} else {StatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha);decorView.addView(statusView);}ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);rootView.setFitsSystemWindows(true);rootView.setClipToPadding(true);setRootView(activity);
}

Android 6.0 + 实现状态栏字色和图标浅黑色

使用沉浸式的时候会遇到一个问题,那就是Android 系统状态栏的字色和图标颜色为白色,当我的主题色或者图片接近白色或者为浅色的时候,状态栏上的内容就看不清了。 这个问题在Android 6.0的时候得到了解决。Android 6.0 新添加了一个属性SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

Alt

解释:为setSystemUiVisibility(int)方法添加的Flag,请求status bar
绘制模式,它可以兼容亮色背景的status bar 。要在设置了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDSflag
,同时清除了FLAG_TRANSLUCENT_STATUSflag 才会生效。

添加如下代码:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}

效果如下:
Alt
除了在代码中添加以外,还可以直接在主题中使用属性:

 <style name="MDTheme" parent="Theme.Design.Light.NoActionBar"><item name="android:windowTranslucentStatus">false</item><item name="android:windowDrawsSystemBarBackgrounds">true</item><item name="android:statusBarColor">@android:color/holo_red_light</item><!-- Android 6.0以上 状态栏字色和图标为浅黑色--><item name="android:windowLightStatusBar">true</item></style>

注意:主题要放在values-v23文件夹下

参考以下文章
Android关于沉浸式状态栏总结
Android适配—沉浸式状态栏
Android App 沉浸式状态栏解决方案
Android 沉浸式解析和轮子使用
Android沉浸式(透明)状态栏适配
Android状态栏微技巧,带你真正理解沉浸式模式
android沉浸式状态栏封装—教你玩出新花样
ImmersionBar – android 4.4以上沉浸式实现


http://chatgpt.dhexx.cn/article/TFyZkELl.shtml

相关文章

图片预览与下载

后端返回base64进行图片的预览和下载下载 有一个图片预览的接口。后端返回的值长这个样子 1、预览 如果要在线预览的话&#xff0c;代码需要这样写放入img的src this.imgPreviewBaseUrl data:image/png;base64, res.data标签中就是这样的 2、下载 图片预览的这样的返…

vue 实现图片预览

vue实现图片预览 现在很多的项目里面图片展示缩略图,然后点击实现图片预览,放大的功能 最近我的项目里面就遇见了这么个场景,我选用了插件进行处理 下面说下实现步骤 1、首先安装插件 npm install vue-photo-preview --save插件地址 2、在main.js里面引入,全局使用 impor…

图片预览器

此预览器&#xff0c;一次只能翻页十张图片&#xff0c;开发人员可根据自己需要&#xff0c;修改前台代码。 页面代码 <% Page Language"C#" AutoEventWireup"true" CodeBehind"UpFilesAndPreview.aspx.cs" Inherits"WebFramework.Comm…

v-viewer图片预览

安装 npm install v-viewer引入 import Viewer from v-viewer import viewerjs/dist/viewer.css Vue.use (Viewer, {defaultOptions: {navbar: true,toolbar: false,movable: false,title: false,zoomable: true,scalable: true,transition: true} })使用 方法一&#xff1a…

vue2图片预览插件

文章目录 学习链接准备工作准备图片与基础的样式PrevImg.vueApp.vue静态效果 封装插件修改PrevImg.vue定义插件逻辑main.js中应用此插件App.vue中使用此插件 图片预览列表修改App.vue修改插件逻辑修改PrevImg.vue 学习链接 vue插件开发实例-图片预览插件 vue2-pre-img-plugin的…

vue 图片预览插件

vue 图片预览插件 步骤 1、先安装依赖 npm install v-viewer --save2、main.js内引用并注册调用 //main.js import Viewer from v-viewer import viewerjs/dist/viewer.cssVue.use(Viewer); Viewer.setDefaults({Options: { "inline": true, "button": …

Vue3图片预览(Image)

本图片预览组件主要包括以下功能&#xff1a; 展示图片时&#xff0c;可设置鼠标悬浮时的预览文本&#xff1b;图像无法加载时要显示的描述&#xff1b;自定义图像高度和宽度&#xff1b;设置图像如何适应容器高度和宽度&#xff08; fill(填充) | contain(等比缩放包含) | cov…

Vue实现图片预览和缩放功能

使用v-viewer插件即可实现图片预览和缩放功能。&#xff08;v-viewer是一款支持vue项目中的图片浏览组件&#xff0c;它支持图片旋转、缩放、翻转等操作&#xff0c;支持配置化.非常强大&#xff09; 安装依赖 执行命令&#xff1a; npm install v-viewer --save 引入并使用…

图片上传预览功能

大多时候我们上传图片&#xff0c;都是直接上传到服务器上&#xff0c;然后返回图片资源所在服务器的路径&#xff0c;然后页面根据这个路径&#xff0c;给图片一个src 属性就能看到图片了。 但是&#xff0c;这样会有一个弊端&#xff1a;如果客户对自己上传的图片不满意&am…

uniapp 图片预览实现

uniapp 图片预览实现 提示&#xff1a;下面案例可供参考 一、app端 使用 uni.previewImage 进行图片预览 可去 uniapp官网 查看具体使用:(https://uniapp.dcloud.net.cn/api/media/image.html#unipreviewimageobject) 二、具体使用如下&#xff08;示例&#xff09;&#xf…

Android中点击图片进行图片预览功能的实现(ImagePreview图片预览工具库)

因为需求&#xff0c;对于轮播图进行一个点击预览的功能&#xff0c;看了好多的文章&#xff0c;都没有弄出来&#xff0c;还是多亏了昊昊猿博主 点击查看原文 终于把它搞定啦。 这里的话是使用ImagePreview&#xff0c;一个非常好用的图片预览工具库&#xff08;还可以实现双…

Vue实现图片预览(Viewer.js)

Viewer.js viewer.js是一款开源的图片预览插件&#xff0c;功能十分强大: 支持移动设备触摸事件 支持响应式 支持放大/缩小 支持旋转&#xff08;类似微博的图片旋转&#xff09; 支持水平/垂直翻转 支持图片移动 支持键盘 支持全屏幻灯片模式&#xff08;可做屏保&#xff0…

前端图片预览怎么做?Vue

选择的图片文件&#xff0c;要给到img标签上纯前端的预览 让用户更近一步看到自己选择的头像 因为img的标签的src的值只能是以下两个 1、只能是图片的“链接地址”&#xff08;外链http://开头&#xff0c;图片文件相对路径&#xff09;(不能发给后台)因为第一种转成http是存…

点击图片实现大图预览

实现点击图片预览 这次主要是在table表格里能够实现&#xff0c;点击里面的图片实现大图预览的效果&#xff0c;直接找的现成的轮子&#xff0c;用在项目里。这里主要是讲讲用viewer组件实现点击图片预览&#xff0c;用的组件&#xff0c;只需在本地安装或者引入。 先看一下&…

ImagePreview 图片预览 的使用​

一、ImagePreview 图片预览 的使用 ImagePreview 是一个函数&#xff08;必须使用按需到处&#xff09;&#xff0c;调用函数后会直接在页面中展示图片预览界面。 // 实现图片预览 import { ImagePreview } from vant 二、处理图片点击预览 思路&#xff1a; 1、从文章内容中…

图片预览(原生js实现)

功能描述 很多网站都是使用浏览器自带图片浏览功能&#xff0c;但看起来很low&#xff0c;想手动实现图片预览功能&#xff0c;点击图片弹出大图预览框在屏幕中间显示&#xff0c;根据图片宽高自适应屏幕大小 效果图 具体代码实现 页面preview.html <!DOCTYPE html> …

图片预览的两种实现方式

做用户头像上传等类似功能的时候&#xff0c;经常会有预览选中图片的需求。在这里介绍两种实现预览的方式。 1.转化为base64格式 通过一种异步文件读取机制FileReader实现。具体步骤是&#xff1a; 创建FileReader对象调用readAsDataURL函数读取文件内容监听FileReader创建的…

CVTE 面试的两道算法题

下了班立马赶往深圳北站&#xff0c;下着大雨又坐过了站&#xff0c;着急地跑向对面的站牌&#xff0c;匆忙间搞得满头大汗。好不容易坐上了高铁&#xff0c;休息片刻&#xff0c;终于有时间整理一下前两天面试CVTE 时遇到的两道算法题。 1. 在数组中寻找和为固定值的两个数字…

CVTE实习求职经历

今天&#xff0c;听到有好多同学最近要去面试CVTE这家企业&#xff0c;于是呢&#xff0c;准备将自己的经历写上来&#xff0c;给大家一个参考&#xff0c;希望能够大家一次帮助。 一、整体感觉 首先呢&#xff0c;先讲一下我个人对这家企业的整体感觉吧。 1. 第一次 对于CVTE这…

CVTE 2016 春季实习校招一面(C++后台)

文章目录 前言问题小结参考文献 前言 2016-03-15 日&#xff0c;参加了 CVTE 的技术一面&#xff0c;很不幸&#xff0c;我和我的两位小伙伴均跪在了一面。先将当日的面试内容汇总如下&#xff0c;供后来者参考。我们三人各自也都总结了失败的原因&#xff0c;大致如下&#x…