前面的文章介绍了如何实现广告轮播的Banner效果,本想可以告一段落。然而某天产品经理心血来潮,拿着苹果手机,要求像iOS那样把广告图顶到状态栏这儿。刚接到这需求,不禁倒吸一口冷气,又要安卓开发去实现iOS的效果,真是强人所难。翻了翻资料,发现修改状态栏的颜色倒是可行,但要把轮播图顶上去就不容易了。再瞅瞅淘宝和当当,原来两个大厂的App都没做出这个效果。正想跟产品经理说这个实现不了,谁料产品大姐笑盈盈地走过来,指着手机说道:“你看,做成京东这样就行了。”盯着手机看了半晌,京东这厮还真的让轮播图插进状态栏了,于是瞬间石化。下面是京东App的首页头部截图:

每当此时,便是程序员最煎熬的时候,人家都做得,为啥你做不得?只好继续寻寻觅觅,又找到另一个电商App,它在Android6.0手机上也完美实现了状态栏悬浮效果,但是在Android4.4手机运行时仍然没能覆盖状态栏。可见这真不是一个省油的灯,许多人用的App尚且未能解决悬浮状态栏的兼容性问题。该电商App的首页截图如下所示,其中左图为Android6.0手机上的运行界面,此时状态栏浮在轮播图上面;右图为Android4.4手机的运行界面,此时状态栏依旧与轮播图泾渭分明。

早期的Android版本姑且不提,Android迟至4.4才开始支持沉浸式状态栏,编码的时候通过Window对象的setAttributes方法来设置窗口属性的标志位。其中标志位WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS用于控制顶部状态栏是否透明,标志位WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION用于控制底部导航栏是否透明。具体的实现代码如下所示:

        // Android4.4的沉浸式状态栏写法Window window = activity.getWindow();WindowManager.LayoutParams attributes = window.getAttributes();int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;// 底部导航栏也可以弄成透明的//int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;attributes.flags |= flagTranslucentStatus;//attributes.flags |= flagTranslucentNavigation;window.setAttributes(attributes);

到了Android5.0之后版本,系统允许直接定制状态栏的颜色,例如调用Window对象的setStatusBarColor方法即可设置顶部状态栏的背景色,调用Window对象的setNavigationBarColor方法即可设置底部导航栏的背景色。不过状态栏的悬浮开关发生了变化,要想让状态栏变透明,最新的方式是调用DecorView对象的setSystemUiVisibility方法来设置标志位。详细的标志位设置代码如下所示:

        // Android5.0之后的沉浸式状态栏写法Window window = activity.getWindow();View decorView = window.getDecorView();// 两个标志位要结合使用,表示让应用的主体内容占用系统状态栏的空间// 第三个标志位可让底部导航栏变透明View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATIONint option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);decorView.setSystemUiVisibility(option);window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

然而以上的处理过程只解决了事情的一个方面,即成功将状态栏悬浮在主页面之上,或者说将主页面沉没到状态栏之下。可是事情的另一方面——把悬浮着的状态栏恢复原状——并没有得到解决,甚至给状态栏换个背景色都不行。譬如说乘船过河,Android时常派了渡船运送乘客,可是当你到达彼岸之后,却发现回程的船只不见了踪影。就恢复状态栏的原状而言,设置标志位是行不通的,幸好过河不一定靠船,还有一招叫做瞒天过海。虽然主页面已经和状态栏重叠在了一起,没法强行把它俩拆散,但我们可以叫主页面让一让,不要跟状态栏挨得这么紧,就是给主页面设置一段顶端空白topMargin,表示主权在我、不妨让你三尺,于是主页面让出一段空白,看起来就与状态栏井水不犯河水了。如此一来,状态栏的悬浮和恢复操作便是可逆的了,如果移除主页面的顶端空白,状态栏就产生悬浮效果;如果添加主页面的顶端空白,状态栏就恢复原状。
对于Android4.4,情况还会更加特殊,因为系统没有提供设置状态栏颜色的方法,所以只能手工搞个假冒的状态栏来占坑。先将这个冒牌状态栏(其内部没有别的控件)染上开发者指定的颜色,然后与系统自带的状态栏重合,于是乎偷梁换柱仿佛给状态栏换了一件衣裳。修改之后的状态栏背景设置代码如下所示(兼容Android4.4,以及5.0以上版本这两种情况):

    // 重置状态栏。即把状态栏颜色恢复为系统默认的黑色public static void reset(Activity activity) {setStatusBarColor(activity, Color.BLACK);}// 设置状态栏的背景色。对于Android4.4和Android5.0以上版本要区分处理public static void setStatusBarColor(Activity activity, int color) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {activity.getWindow().setStatusBarColor(color);// 底部导航栏颜色也可以由系统设置//activity.getWindow().setNavigationBarColor(color);} else {setKitKatStatusBarColor(activity, color);}if (color == Color.TRANSPARENT) { // 透明背景表示要悬浮状态栏removeMarginTop(activity);} else { // 其它背景表示要恢复状态栏addMarginTop(activity);}}}private static final String TAG_FAKE_STATUS_BAR_VIEW = "statusBarView";private static final String TAG_MARGIN_ADDED = "marginAdded";// 添加顶部间隔,留出状态栏的位置private static void addMarginTop(Activity activity) {Window window = activity.getWindow();ViewGroup contentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);View child = contentView.getChildAt(0);if (!TAG_MARGIN_ADDED.equals(child.getTag())) {FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) child.getLayoutParams();// 添加的间隔大小就是状态栏的高度params.topMargin += getStatusBarHeight(activity);child.setLayoutParams(params);child.setTag(TAG_MARGIN_ADDED);}}// 移除顶部间隔,霸占状态栏的位置private static void removeMarginTop(Activity activity) {Window window = activity.getWindow();ViewGroup contentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);View child = contentView.getChildAt(0);if (TAG_MARGIN_ADDED.equals(child.getTag())) {FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) child.getLayoutParams();// 移除的间隔大小就是状态栏的高度params.topMargin -= getStatusBarHeight(activity);child.setLayoutParams(params);child.setTag(null);}}// 对于Android4.4,系统没有提供设置状态栏颜色的方法,只能手工搞个假冒的状态栏来占坑private static void setKitKatStatusBarColor(Activity activity, int statusBarColor) {Window window = activity.getWindow();ViewGroup decorView = (ViewGroup) window.getDecorView();// 先移除已有的冒牌状态栏View fakeView = decorView.findViewWithTag(TAG_FAKE_STATUS_BAR_VIEW);if (fakeView != null) {decorView.removeView(fakeView);}// 再添加新来的冒牌状态栏View statusBarView = new View(activity);FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));params.gravity = Gravity.TOP;statusBarView.setLayoutParams(params);statusBarView.setBackgroundColor(statusBarColor);statusBarView.setTag(TAG_FAKE_STATUS_BAR_VIEW);decorView.addView(statusBarView);}

总算大功告成,接着看看实际的运行效果,具体如下图所示。由于上述代码同时兼容Android4.4,以及5.0以上版本这两种情况,因此就不重复贴图了。其中左图为悬浮状态栏的效果图,右图为恢复状态栏的效果图。

点此查看Android开发笔记的完整目录

__________________________________________________________________________
本文现已同步发布到微信公众号“老欧说安卓”,打开微信扫一扫下面的二维码,或者直接搜索公众号“老欧说安卓”添加关注,更快更方便地阅读技术干货。

Android开发笔记(一百六十三)高仿京东的沉浸式状态栏相关推荐

  1. Android开发笔记(六十三)HTTP访问的通信方式

    InputStream和OutputStream 输入输出流在java中很常用,从文件读写到内存读写到网络通信都会用到.在之前的< Android开发笔记(三十三)文本文件和图片文件的读写> ...

  2. Android开发笔记(六十一)文件下载管理DownloadManager

    下载管理DownloadManager 文件下载其实是网络数据访问的一种特殊形式,使用普通的http请求也能完成,就是实现起来会繁琐一些.因为下载功能比较常用,而且业务功能相对统一,所以从Androi ...

  3. Android开发笔记(四十三)点击事件

    按钮点击 常用按钮点击 1.单击事件,主要用于Button和ImageButton控件,布局视图与TextView.ImageView控件用的也比较多.相关类名与方法说明如下: 监听器类名 : Vie ...

  4. Android开发笔记(八十三)多语言支持

    汉字转拼音 app中有许多场景要对汉字排序,例如通讯录姓名.商品名称.城市名称等等,这些汉字词汇通常是按照拼音排序,所以产生了把汉字转换为拼音的需求. Android自带库 Android自带的联系人 ...

  5. Android开发笔记(七十三)代码混淆与反破解

    代码混淆 ProGuard是ADT自带的apk混淆器,它的用途有: 1.压缩apk包的大小,能删除无用的代码,并简化部分类名和方法名. 2.加大破解源码的难度,因为部分类名和方法名被重命名,使得程序逻 ...

  6. Android开发笔记(二十三)文件对话框FileDialog

    日期和时间对话框 对话框是人机交互的有力工具,Android自带了几个常用的对话框,包括AlertDialog提示对话框.ProgressDialog进度对话框.DatePickerDialog日期选 ...

  7. Android开发笔记(六十二)HTTP数据格式的解析

    json解析 android有两种主流的json解析方案,一种是sdk自带的由Google提供的json(包名前缀为org.json),另一种是Alibaba提供的第三方jar包fastjson(包名 ...

  8. Android开发笔记(六十六)自定义对话框

    AlertDialog Android中最常用的对话框是AlertDialog,它可以完成常见的交互操作,如提示.确认.选择等等,然后就是进度对话框ProgressDialog(参见< Andr ...

  9. Android开发笔记(六十五)多样的菜单

    菜单Menu Android的菜单分为两类:选项菜单和上下文菜单,默认使用选项菜单.菜单的布局文件存放在res/menu目录下,使用ADT新建一个Android工程,首页代码MainActivity中 ...

最新文章

  1. [JS]题解 | #魔法数字#
  2. python面向对象小练习
  3. P2550 [AHOI2001]彩票摇奖
  4. nginx绑定IP的坑
  5. 【杂题总结】洛谷-3959 宝藏
  6. http 1.php,php – Nginx忽略客户端的HTTP 1.0请求并通过HTTP 1.1响应
  7. Ubuntu把iso写入U盘
  8. Windows Server 2003 系统安装
  9. Linux 命令(134)—— groupmod 命令
  10. 把变量赋值给寄存器_阻塞赋值和非阻塞赋值的区别与记忆
  11. OpenCV之图像混合
  12. Hibernate的SQL查询
  13. 关于sql 拼接字符串的问题
  14. 华龙电音基调网_华龙电音基调查询器下载(最好用的电音基调查询器) v1.4免费版...
  15. WeCode在线少儿编程|为什么我们选择代码编程
  16. 二维码名片的格式 - vcard(非常好,可直接添加到手机通讯录)
  17. Linux本地网络软件仓库搭建
  18. 《不要等到毕业以后》读书笔记
  19. 7-28 猴子选大王(20 分)
  20. 沧海一声笑计算机版本,各个版本的《沧海一声笑》,古韵十足

热门文章

  1. 吴恩达深度学习之一《神经网络和深度学习》学习笔记
  2. Huffman编码树
  3. POJ1321(深搜)
  4. 直观理解:为什么A为 n 阶满秩方阵时,Ax=0 只有零解?
  5. MFC中App、Doc、MainFrame、View各指针的互相获取
  6. LeetCode刷题(4)
  7. Python2解决的中文乱码问题
  8. android json字符串转成json对象_在PHP中处理JSON数组以及对象
  9. 若依使用undertow来替代tomcat容器
  10. 第2章[2.4] Ext JS的类与类体系