固定导航栏android,Android 状态栏和导航栏的真终极解决方案
去年我写过一篇文章,透明状态栏和导航栏的终极解决方案,并在 Github 上开源了代码,https://github.com/Zackratos/UltimateBar,其实在那之后,我一直对这个项目进行维护和更新,最近,我又用 kotlin 重构了代码,并加入了一些新的功能,代码改动比较大,特意写篇文章介绍一下,希望这个库能给做 Android 开发的同学带来帮助。
旧版本的缺陷
事实上,这次重构之后已经是 3.0 版本了,之前重构 2.0 版本的时候已经有了大幅度的修改,但 2.0 版的重构主要是对代码的优化,方便开发者的调用,比如采用 Builder 模式进行配置参数。而这次的重构,在功能上做了很大的修改,可以适用于更多的场景。
旧版本主要有 3 个缺陷。
参数过多。旧版本中设置状态栏和导航栏的颜色的时候,参数包括了色值和透明度以及颜色的深度,导致调用的时候需要传入大量的参数,其实这些完全没必要,透明度和颜色深度都是可以包含在色值里面的,严格来说,只要传入一个参数就好了,至于它的透明度和深度,如果需要,开发者可以自己设置好之后再传入。
同一个 Activity 只能设置一次。旧版本中一般需要使用透明状态栏和导航栏的时候,都是在 onCreate 中设置,然后就固定了,但是如果有时候需要在 Activity 中再次设置不同的效果,就会力不从心了。
不支持灰色模式。我们知道, Android 6.0 以上是支持状态栏灰色模式的,就是把状态栏种的字体颜色改为灰色,这种模式是为了避免在白色界面上设置沉浸状态栏导致状态栏的字体看不见的尴尬的,但是旧版本中并没有对这种情况进行适配。
新版本的改进
针对旧版本的缺陷,新版本主要做了以下改进。
去除多余的参数。新版本中状态栏和导航栏的背景都只需要一个参数,参数类型是 Drawable,相对于 Color 来说,Drawable 明显更加灵活,不但可以设置状态栏和导航栏的颜色,而且可以设置透明度,还有渐变色等各种效果,也就是说,只要是 Drawable 能实现的效果,都能设置到状态栏和导航栏上。
支持多次设置。新版本中调整了代码的逻辑,现在可以对状态栏和导航栏的效果进行多次设置了,但是 UltimateBar 有四种效果,多次设置只能对同一种效果有效。比如说,如果你第一次设置了半透明的状态栏和导航栏,那么后面要修改,也只能设置半透明的效果,如果设置其他效果会出现不可预知的问题。
支持灰色模式,分别对 Android 6.0 以上和 Android 8.0 以上适配了状态栏灰色模式和导航栏灰色模式,避免白色界面状态栏字体看不见的尴尬。
使用
UltimateBar 的使用非常简单,首先在 gradle 中添加依赖
implementation 'com.github.zackratos.ultimatebar:ultimatebar3:3.0.0'
如果你要直接给状态栏和导航栏设置一个背景,在 onCreate 中
UltimateBar.Companion.with(this)
.statusDark(false) // 状态栏灰色模式(Android 6.0+),默认 flase
.statusDrawable(drawable) // 状态栏背景,默认 null
.applyNavigation(true) // 应用到导航栏,默认 flase
.navigationDark(false) // 导航栏灰色模式(Android 8.0+),默认 false
.navigationDrawable(drawable) // 导航栏背景,默认 null
.create()
.drawableBar();
如果要给状态栏和导航栏设置半透明效果,在 onCreate 中
UltimateBar.Companion.with(this)
.statusDark(false) // 状态栏灰色模式(Android 6.0+),默认 flase
.statusDrawable(drawable) // 状态栏背景,默认 null
.applyNavigation(true) // 应用到导航栏,默认 flase
.navigationDark(false) // 导航栏灰色模式(Android 8.0+),默认 false
.navigationDrawable(drawable) // 导航栏背景,默认 null
.create()
.transparentBar();
注意这里的 statusDrawable 和 navigationDrawable 的参数必须是半透明的,因为此时 contentView 会延伸到状态栏和导航栏上面,如果不是半透明的,会把 contentView 盖住。
如果要设置沉浸式状态栏和导航栏,在 onCreate 中
UltimateBar.Companion.with(this)
.statusDark(false) // 状态栏灰色模式(Android 6.0+),默认 flase
.applyNavigation(true) // 应用到导航栏,默认 flase
.navigationDark(false) // 导航栏灰色模式(Android 8.0+),默认 false
.create()
.immersionBar();
其实这就是第二种效果的特殊情况,即 statusDrawable 和 navigationDrawable 都为 null。
如果要隐藏状态栏和导航栏,需要重写 onWindowFocusChanged 方法
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
UltimateBar.Companion.with(this)
.applyNavigation(true) // 是否应用到导航栏
.create()
.hideBar();
}
}
如果使用了 DrawerLayout,需要实现 DrawerLayout 的主布局被覆盖,而抽屉需要沉浸的效果,可以在 onCreate 中
UltimateBar.Companion.with(this)
.statusDark(false) // 状态栏灰色模式(Android 6.0+),默认 flase
.statusDrawable(drawable) // 状态栏背景,默认 null
.applyNavigation(true) // 应用到导航栏,默认 flase
.navigationDark(false) // 导航栏灰色模式(Android 8.0+),默认 false
.navigationDrawable(drawable) // 导航栏背景,默认 null
.create()
.drawableBarDrawer(drawerLayout, // DrawerLayout
content, // DrawerLayout 的主布局 View
drawer); // DrawerLayout 的抽屉布局 View
以上所有的方法,如果是在 kotlin 中使用,都可以省略 Companion 关键词,并且 kotlin 中可以用如下方式调用
with().statusDark(false) // 状态栏灰色模式(Android 6.0+),默认 flase
.statusDrawable(drawable) // 状态栏背景,默认 null
.applyNavigation(true) // 应用到导航栏,默认 flase
.navigationDark(false) // 导航栏灰色模式(Android 8.0+),默认 false
.navigationDrawable(drawable) // 导航栏背景,默认 null
.create()
.drawableBar();
with() 就相当于 UltimateBar.Companion.with(this)。
如果要在 Fragment 中使用,可以先设置 Fragment 所在的 Activity 沉浸,然后再设置 Fragment, 可以参考 demo 中的写法。
终极方案
在实际开发中,有时会遇到一些奇葩的需求,各种复杂的情况叠加,这时候可以采用终极解决方案,就是先把状态栏和导航栏都设置为沉浸式,然后通过在状态栏和导航栏的位置加一个自定义背景的 View 和应对复杂的业务场景,具体使用可参考 demo。
简单原理
状态栏和导航栏的主要难点是 Android 4.4 和 Android 5.0 以上的实现方法不一样,要达到一致的效果,必须进行版本适配。
在 Android 4.4 上只能设置状态栏和导航栏透明,如果要设置它们的背景,必须在状态栏和导航栏的位置手动添加一个 View,并设置 View 的背景来充当状态栏和导航栏的背景,而在 Android 5.0 以上,可以直接设置状态栏和导航栏的背景色。
但是在 Android 5.0 以上的 Api 中,状态栏和导航栏的背景只能设置为 Color,不能是 Drawable,为了设置 Drawable,在 Android 5.0 以上,同样先设置状态栏和导航栏透明,然后也在状态栏和导航栏的位置上添加一个 View,用 View 的背景来充当状态栏和导航栏的背景,从而可以直接设置为 Drawable。
为什么不把状态栏和导航栏分开设置
其实在重构 2.0 版本的时候,我就考虑把状态栏和导航栏分开,分别设置,互不影响,这样代码更优雅,调用起来也更方便,但是后来发现一个问题,就是导航栏不能单独设置,如果单独设置了导航栏沉浸,状态栏也会出现沉浸的效果。但是可以单独设置状态栏沉浸,导航栏保持原状,基于此原因,UltimateBar 设计为统一的 Api,然后通过参数 applyNavigation 来确定要不要应用到导航栏中。
不过我现在又想到一个分开设置的野路子方法,就是每种情况都先设置成沉浸的效果,然后通过修改 mContentParent 的 paddingTop 和 paddingBottom 来设置状态栏和导航栏的效果,这样就可以把状态栏和导航栏分开来设置了,可以考虑在下个版本中使用这种方法。
存在的不足
目前 UltimateBar 还存在以下几点不足。
前面提到的,多次设置只能针对同一种效果,不同效果会有不可预估的问题,不过绝大多数情况下不会有这样的需求。
也是前面提到的,状态栏和导航栏没有分开设置,现在只能单独设置状态栏或者同时设置状态栏和导航栏,不能单独设置导航栏,不过绝大多数情况不会有单独设置导航栏这种奇葩的需求。
现在的状态栏灰色模式只支持 Android 6.0 以上,因为官方是 Android 6.0 才开始支持的,但其实 miui 和 flyme 从 Android 4.4 就开始支持了,但是由于我身边没有相应的设备,不好测试,所以暂时没有针对 miui 和 flyme 做专门的适配。
以上三点不足,其实都影响不大,之所以称它们为“不足”,而不是“问题”,就是因为影响很小,不夸张的说,UltimateBar 绝对可以满足绝大多数需求。
最后,奉上 Github 地址
欢迎 star、fork,提 issue、pull request。
固定导航栏android,Android 状态栏和导航栏的真终极解决方案相关推荐
- Android隐藏状态栏、导航栏
Android隐藏状态栏.导航栏 [java] view plaincopy private void hideStatusNavigationBar(){ if(Build.VERSION.SDK_ ...
- android应用去掉状态栏_Android 显示、隐藏状态栏和导航栏
Android 显示.隐藏状态栏和导航栏 控制状态栏显示,Activity的主题中配置全屏属性 true 控制状态栏显示,在setContentView之前设置全屏的flag getWindow(). ...
- Android 显示、隐藏状态栏和导航栏
Android 显示.隐藏状态栏和导航栏 控制状态栏显示,Activity的主题中配置全屏属性 <item name="android:windowFullscreen"&g ...
- android ui状态栏高度,Android--状态栏高度,导航栏高度,Window高度,DecorView高度,heightPixels...
1:DecorView的高度 DecorView的高度代表的是: 整个装饰窗口的高度, 这个高度包括:状态烂的高度和导航栏的高度.(状态栏和导航栏通常叫做装饰窗口, 而ActionBar不属于装饰窗口 ...
- 【干货】Android系统定制基础篇:第十三部分(开放root权限、禁止应用旋转、隐藏状态栏和导航栏)
一.Android开放root权限 Android 5.1 1.修改 su 源码(system\extras\su\su.c),注释下面代码: int main(int argc, char **ar ...
- android安卓导航栏高度是多少,Android--状态栏高度,导航栏高度,Window高度,DecorView高度,heightPixels...
喔...这标题,吓我一跳; 请稍等.... 思绪整理中... Android中, 经常被这些高度绊脚. 完全进入懵逼的状态, 有木有? 请允许我,介绍清楚! 通常情况下, 宽度都是很友好的,但是高度就 ...
- Android 5.0状态栏和导航栏
Material Design推出之后,app中也開始沿用这样的风格 今天来说一下状态栏颜色设置,在4.4的时候推出了透明状态栏和导航栏.在不使用第三方库的情况下,4.4还是没有全然解决存在actio ...
- android 电话 状态栏,Android透明式状态栏、导航栏实现
有很多应用有透明式状态栏.导航栏,表现形式是在不同页面里,状态栏可以与最上面的背景图片或者颜色保持一致.典型的案例就是手Q:(如图所示) 很明显,在手Q中主要的几个页面的标题栏(ActionBar位置 ...
- Android 7.0 SystemUI 之启动和状态栏和导航栏简介
Android 7.0 SystemUI 之启动和状态栏和导航栏简介 一.SystemUI 是什么 首先SystemUI 是一个系统应用,apk路径位于/system/priv-app 源码路径位于: ...
最新文章
- 合成大西瓜html源码,index.html
- Dispatcher initialization failed解决办法
- T-SQL中REPLACE的用法_字符串替换
- eclipse加速之禁用JS、jsp等文件的语法验证
- printf参数的问题
- 408考研复试之计算机组成原理笔记第一二三章
- Linux驱动开发之触摸驱动
- 20190926-win10电脑声音麦克风设置里没有增强属性怎么办听语音
- 医院时钟系统(网络授时设备)设计方案
- 局域网网络流量监控_【网络监控与安全】主要网络流量处理技术
- RT进程组的cpu带宽限制
- 支付宝app支付,订单参数错误/PHP生成支付宝预支付订单/php 支付宝app支付
- 一元二次方程的解的程序
- 分奖金(python)
- Android手机直播(一)总览
- 关于input框的兼容性问题
- [JQuery实现] 测测你今天的运势如何?(程序猿老黄历)
- UNI-APP_在uni-app中引入和使用uViewUI
- 华为云,用科技开启智慧化生活
- 深入学习设计模式之---单例模式
热门文章
- 有初学的同学问你为什么Java的main方法必须是public static void?请告诉ta!
- 大剑无锋之简单介绍一下虚拟内存【面试推荐】
- 大剑无锋之内存泄漏是什么?【面试推荐】
- 【PAT甲级 进制转换】1019 General Palindromic Number (20 分) Java版 7/7通过
- 分布式系统原理 之3 Lease机制
- java安全编码指南之:Thread API调用规则
- Leet Code OJ 242. Valid Anagram [Difficulty: Easy]
- 08.suggester02term_suggester
- Mining Precision Interface From Query Logs -- 学习笔记(二)
- 1096 Consecutive Factors (20 分)_24行代码AC