XZNavigationController 为原生的 UINavigationController 组件拓展了自定义导航条的功能,并且与原生导航条兼容。
要开启自定义导航条支持,UINavigationController 只需遵循 XZNavigationController 协议即可,无需改变基类,不会带来额外风险。
// 让您的控制器遵循协议,即可获得自定义导航栏开关属性
class ExampleNavigationController: UINavigationController, XZNavigationController {
override func viewDidLoad() {
super.viewDidLoad()
// 打开自定义导航栏开关
self.isNavigationBarCustomizable = true
}
}
仅需视图遵循 XZNavigationBarProtocol
协议,即可作为控制器的自定义导航条。为了方便开发,框架内置了 XZNavigationBar
基类,以此进行开发,自定义导航条更简单。
框架默认不会提供自定义导航条,基类
XZNavigationBar
只是一个开发选项,自定义导航条仅需要遵循协议即可,并非必须以它为基类。
以下示例代码中,
public class ExampleNavigationBar: XZNavigationBar {
public var title: String? {
get {
return (self.titleView as? UILabel)?.text
}
set {
if titleView == nil {
// 1. 配置 titleLabel 和 largeTitleLabel
...
// 2. largeTitleLabel 可以直接作为 largeTitleView,但示例中,为了要实现覆盖的效果额外增加一个容器视图
let largeTitleView = UIView.init(frame: CGRect(x: 0, y: 0, width: width, height: 52))
largeTitleView.addSubview(largeTitleLabel)
// 3. 使用 XZNavigationBar 只需要赋值 titleView 和 largeTitleView 即可,布局会自动进行
self.titleView = titleLabel
self.largeTitleView = largeTitleView
}
titleLabel.text = newValue
largeTitleLabel.text = newValue
}
}
private let titleLabel = UILabel.init()
private let largeTitleLabel = UILabel.init()
}
XZNavigationBar
已实现了XZNavigationBarProtocol
协议,因此不需要额外实现。不过XZNavigationBarProtocol
协议的实现并不复杂,只需定义两个属性即可,这两个属性会影响导航条布局,因此需要额外实现。
public protocol XZNavigationBarProtocol: UIView {
var isTranslucent: Bool { get set }
var prefersLargeTitles: Bool { get set }
}
在控制器中使用自定义导航条,仅需控制器实现 XZNavigationBarCustomizable
协议即可。
public protocol XZNavigationBarCustomizable: UIViewController {
var navigationBarIfLoaded: XZNavigationBarProtocol? { get }
}
没错这个协议,仅需实现一个属性。这个属性实际上是告诉框架,控制器创建了自定义导航条后,框架要通过哪个属性去获取它。
利用 Swift 面向协议的特性,我们可以创建一个拓展,使遵循协议的控制器自动获得统一的自定义导航条。
extension XZNavigationBarCustomizable {
public var navigationBarIfLoaded: XZNavigationBarProtocol? {
return self.navigationBar
}
public var navigationBar: ExampleNavigationBar {
if let navigationBar = objc_getAssociatedObject(self, &_navigationBar) as? ExampleNavigationBar {
return navigationBar
}
let navigationBar = ExampleNavigationBar(for: self, frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 0))
objc_setAssociatedObject(self, &_navigationBar, navigationBar, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return navigationBar
}
}
这样在控制器中我们就可以直接使用了。
class ExampleLastViewController: UITableViewController, XZNavigationBarCustomizable {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationBar.title = "尾页"
self.navigationBar.barTintColor = .systemBrown
}
}
示例中我们直接使用的是 navigationBar
属性,而不是 XZNavigationBarCustomizable
协议中的 navigationBarIfLoaded
属性,这是因为 IfLoaded
是一个泛型对象,在上面的拓展中,我们用具体的 navigationBar
类型进行中转,这样我们就不需要进行类型转换了。
原生 UINavigationController 对手势返回的使用条件比较苛刻,因此 XZNavigationController 改进了这一功能。
- 默认情况下始终支持手势返回。
- 支持手势导航前进到下一个页面。
- 支持手势导航返回到任意页面。
- 支持限制导航行为。
要支持上述功能,只需遵循 XZNavigationGestureDrivable
协议即可。
public protocol XZNavigationGestureDrivable: UIViewController {
func navigationController(_ navigationController: UINavigationController, edgeInsetsForGestureNavigation operation: UINavigationController.Operation) -> NSDirectionalEdgeInsets?
func navigationController(_ navigationController: UINavigationController, viewControllerForGestureNavigation operation: UINavigationController.Operation) -> UIViewController?
}
协议的第一个方法通过控制边距即可控制手势导航是否触发;实现第二个方法则可以在手势导航时,跳转到任何页面;具体可以在代码中查看方法注释。
要运行示例项目,请先从仓库中克隆,然后再从 Pods 目录运行 pod install
iOS 11.0, Xcode 14.0
XZNavigationController 通过 CocoaPods 可用。要安装它,只需在 Podfile 中添加以下行即可
pod 'XZNavigationController'
Xezun, [email protected]
XZNavigationController 基于 MIT 许可证。有关更多信息,请参阅 LICENSE 文件。