代码地址:GitHub 仓库 - HideNavigationbarDemo
以前的沉浸式做法有很多,比如拿到 navigationBar
的 backgroundImage
修改透明度,或者往 navigationBar
的view
层加一个占位的视图,修改这个占位视图的透明度在视觉上形成直接修改navigationBar
的效果。
上面的做法我都试过,也许是版本过时了。第一种 navigationBar.subviews.first
已经不是backgroundImage
(似乎IOS11之后已经被修改了);第二种方法,占位视图通过insertSubview
加入后,会阻挡navigationItem
上的标题和图标。
我在第二种方法的基础上做了修改,既然直接在 navigationBar
添加占位视图会阻挡标题,那就直接内容视图里添加,反正导航栏已经设置成透明的,只要这个占位视图在放在导航栏正下方,视觉上其实是一样的。
但做下去发现,每次退出页面都要恢复导航栏的样式,毕竟导航栏是多个页面共用(除非你每一个页面前都新建一个Navigation Controller
,那就当我没说~),可是恢复透明度、背景图片巴拉巴拉的又是一堆代码,而且还有视觉上的巨大不协调性,如果每次退出都要重设一大堆东西,那也太不灵活了。我相信90%的程序员都会被这个恢复搞到头昏脑胀(包括我)。
于是想到,既然背景的透明渐变效果我都能用占位视图模拟,那干脆隐藏系统的导航栏,用新的NavigationBar
,这样就不需要考虑恢复透明度、重设背景图片、shadow图片巴拉巴拉的问题,而只是隐藏和不隐藏的操作,一行代码的事。嗯,真香。
代码
如果你很聪明,只看下面的代码自己就能完成所有的效果。如果你和我一样懒,不想管那么多逻辑,直接Copy保存到一个swift文件,然后跳过这一节,直接看Demo是怎么使用的吧。
private var navBarHolderViewKey = "navBarHolderViewKey"
private var navBarBackgroundViewKey = "navBarBackgroundViewKey"
private var navBarViewKey = "navBarViewKey"
extension UIViewController {
fileprivate var navBarHolder: UIView? {
set {
objc_setAssociatedObject(self, &navBarHolderViewKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &navBarHolderViewKey) as? UIView
}
}
// 计算属性保存自定义的导航栏
var customNavigationBar: UINavigationBar? {
set {
objc_setAssociatedObject(self, &navBarViewKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}