-
目标效果图:
如上图效果: push 和 pop的时候 导航条均有层次结构
第一步: 项目中自定义导航控制器, 继承自UINavigationController, 用来管理所有界面, 效果如图:
- 第二步: 在自定义的导航控制器中隐藏默认的导航条
override func viewDidLoad() {
super.viewDidLoad()
// 隐藏默认的NavigationBar
self.navigationBar.isHidden = true
}
- 第三步: 导航条所有的子控制器都继承自一个基类, 这个基类继承自UIViewController, 在这个基类中设置UINavigationBar和UINavigationItem的属性, 添加UINavigationBar到view上, 并重写title属性的setter方法, 在设置title的时候, 配置自定义的UINavigationItem属性的title, 效果图如下:
- 代码如下:
import UIKit
class BWBaseViewController: UIViewController {
// 自定义导航条
lazy var navigationBar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: UIScreen.width(), height: 64))
lazy var navItem: UINavigationItem = UINavigationItem()
// 重写 title 的 didSet方法
override var title: String? {
didSet {
navItem.title = title
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.cz_random()
// 将导航条 添加到 view上
view.addSubview(navigationBar)
// 将 navItem 设置给 navigationBar
navigationBar.items = [navItem]
// 设置 navBar 的渲染颜色
navigationBar.barTintColor = UIColor.white
}
}
- 第四步: 在自定义的导航控制器中, 拦截push方法, 给即将push的控制器添加返回按钮, 返回按钮文字使用上一个界面的标题, 如果没有标题就是用"返回"二字, 效果图如下:
- 代码:
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
if childViewControllers.count > 0 {
// 判断控制器类型 (多态)
if let viewController = viewController as? BWBaseViewController {
// 获取 导航控制器栈里最后一个控制器, 这里第一个控制器也是BWBaseViewController类型
let vc = childViewControllers[childViewControllers.count - 1] as! BWBaseViewController;
// 获取标题, 没有就是用 "返回", 这个标题在返回按钮上使用
var title = vc.navItem.title ?? "返回"
// 设置返回按钮, 使用 "上一个界面的标题", 没有就是用 "返回"
viewController.navItem.leftBarButtonItem = UIBarButtonItem.item(
imageName: "navigationbar_back_withtext",
highlightedImageName: "navigationbar_back_withtext_highlighted",
title : title,
titleColor : UIColor.color(red: 96, green: 96, blue: 96),
highlightedTitleColor : UIColor.color(red: 253, green: 130, blue: 36),
font : UIFont.systemFont(ofSize: 19),
target: self,
action: #selector(back))
}
// 隐藏底部tabBar
viewController.hidesBottomBarWhenPushed = true
}
super.pushViewController(viewController, animated: animated)
}
@objc private func back() {
popViewController(animated: true)
}
- 第五步: 目标效果是根控制器除外, 第一个push的控制器返回按钮使用 首页标题二字, 其他界面均使用 返回二字, 所以在设置标题时需要进行判断:
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
if childViewControllers.count > 0 {
// 判断控制器类型 (多态)
if let viewController = viewController as? BWBaseViewController {
// 获取 导航控制器栈里最后一个控制器, 这里第一个控制器也是BWBaseViewController类型
let vc = childViewControllers[childViewControllers.count - 1] as! BWBaseViewController;
// 获取标题, 没有就使用 "返回", 这个标题在返回按钮上使用
var title = vc.navItem.title ?? "返回"
// 第二层开始, 统一用 "返回"
if childViewControllers.count > 1 {
title = "返回"
}
// 设置返回按钮, 使用 "上一个界面的标题", 没有就是用 "返回"
viewController.navItem.leftBarButtonItem = UIBarButtonItem.item(
imageName: "navigationbar_back_withtext",
highlightedImageName: "navigationbar_back_withtext_highlighted",
title : title,
titleColor : UIColor.color(red: 96, green: 96, blue: 96),
highlightedTitleColor : UIColor.color(red: 253, green: 130, blue: 36),
font : UIFont.systemFont(ofSize: 19),
target: self,
action: #selector(back))
}
// 隐藏底部tabBar
viewController.hidesBottomBarWhenPushed = true
}
super.pushViewController(viewController, animated: animated)
}
第六步: 以后所有的导航条设置, 都直接使用 属性 navItem 即可, 不要在作用系统默认的导航条属性 navigationItem
以上就是目标效果的思路
最后: 实现这种效果的方式有很多种, 这只是其中一个方案而已