Ios 如何在Swift中实现自定义NavigationController
我有一个应用程序,它使用NavigationController和TabBarController在不同的视图中轻松导航。对于某些视图,我有一个标题和一些按钮(有时只在右侧,有时在右侧和左侧)。但是,对于某些视图,例如在观看某人的个人资料时,我不想设置标题。我想显示个人资料图片,并在图片下方添加用户名 我的问题很简单:我是否应该使用NavigationController来实现这一点,因为我希望配置文件图片“覆盖”NavigationController,使其与状态栏的距离仅为16像素,而不是与NavigationController的距离。在仍然有左键和右键的情况下,这是可能的(例如,编辑您自己的配置文件,或者编辑“更多选项”按钮) 我一直在考虑使用一种完全不同的方法,不使用NavigationController,而是在必要时使用标签来显示标题,并在左侧和右侧添加视图,以便在必要时添加按钮 由于这是我第一次做这样的事情,我很想听听你对如何实现这一结果以及最佳实践的看法。有些事情告诉我,最好使用NavigationController,因为这就是它的目的,但是我如何实现可选标题并在需要时检查它呢?我已经知道如何去除底部发际线以及如何相应地设置背景色,所以这不是最大的问题。我只关心如何在NavigationController上显示图像Ios 如何在Swift中实现自定义NavigationController,ios,swift,uinavigationcontroller,user-profile,Ios,Swift,Uinavigationcontroller,User Profile,我有一个应用程序,它使用NavigationController和TabBarController在不同的视图中轻松导航。对于某些视图,我有一个标题和一些按钮(有时只在右侧,有时在右侧和左侧)。但是,对于某些视图,例如在观看某人的个人资料时,我不想设置标题。我想显示个人资料图片,并在图片下方添加用户名 我的问题很简单:我是否应该使用NavigationController来实现这一点,因为我希望配置文件图片“覆盖”NavigationController,使其与状态栏的距离仅为16像素,而不是与
谢谢大家 创建自定义“标题标签”的最佳方法是对
UIView
和UINavigationController
进行子类化。这方面的演示是
主要部件包括导航控制器。基本上,您希望将title
属性保留为空(一个空字符串或不设置它),并且由于UINavigationController
只是UIViewController
的一个子类,作为具有push/pop功能的容器视图工作,因此可以以这种方式使用您的子类。在我的演示中,我的子类nav控制器类被称为NavigationController
在我看来,您从子类化UINavigationController
中获得的主要优势是使用它的push/pop功能。。。虽然你可以使用segues,但它们需要一个故事板,虽然你可以使用UIView
动画,但我觉得它并不“流畅”
(1)如果您没有使用情节提要,请记住在AppDelegate
:
var navController: NavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
navController = NavigationController(nibName: nil, bundle: nil)
self.window!.rootViewController = navController
self.window?.makeKeyAndVisible()
return true
}
class NavigationController:UINavigationController {
let redVC = RedViewController()
let greenVC = GreenViewController()
let titleView = TitleView()
var titleViewHeightConstraint:NSLayoutConstraint!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
pushViewController(redVC, animated: false) // display the first VC
}
func popGreenVC() {
popViewController(animated: true)
}
func pushGreenVC() {
pushViewController(greenVC, animated: true)
}
}
class RedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.red
let showGreenVC = UIBarButtonItem(title: "Green \u{25B6}", style: .plain, target: self, action: #selector(pushGreenVC))
self.navigationItem.rightBarButtonItem = showGreenVC
}
@objc func pushGreenVC() {
let navController = self.navigationController as! NavigationController
navController.pushGreenVC()
}
}
class GreenViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.green
let showRedVC = UIBarButtonItem(title: "\u{25C0} Red", style: .plain, target: self, action: #selector(popGreenVC))
self.navigationItem.leftBarButtonItem = showRedVC
}
@objc func popGreenVC() {
let navController = self.navigationController as! NavigationController
navController.popGreenVC()
}
}
class TitleView: UIView {
let yellowView = UIView()
let blueView = UIView()
convenience init() {
self.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
yellowView.translatesAutoresizingMaskIntoConstraints = false
blueView.translatesAutoresizingMaskIntoConstraints = false
yellowView.backgroundColor = UIColor.yellow
blueView.backgroundColor = UIColor.blue
self.addSubview(yellowView)
self.addSubview(blueView)
yellowView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
yellowView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
yellowView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
yellowView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
blueView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
blueView.leadingAnchor.constraint(equalTo: yellowView.trailingAnchor).isActive = true
blueView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
blueView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
}
func changeTitleViewHeight(to:CGFloat) {
titleViewHeightConstraint.constant = to - view.safeAreaInsets.top
}
override func viewSafeAreaInsetsDidChange() {
let navController = self.navigationController as! NavigationController
navController.changeTitleViewHeight(to: view.safeAreaInsets.top)
}
(2)虽然还有其他方法可以做到这一点,但我更喜欢在我的子类中实例化视图控制器,根据需要将方法公开给push/pop:
var navController: NavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
navController = NavigationController(nibName: nil, bundle: nil)
self.window!.rootViewController = navController
self.window?.makeKeyAndVisible()
return true
}
class NavigationController:UINavigationController {
let redVC = RedViewController()
let greenVC = GreenViewController()
let titleView = TitleView()
var titleViewHeightConstraint:NSLayoutConstraint!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
pushViewController(redVC, animated: false) // display the first VC
}
func popGreenVC() {
popViewController(animated: true)
}
func pushGreenVC() {
pushViewController(greenVC, animated: true)
}
}
class RedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.red
let showGreenVC = UIBarButtonItem(title: "Green \u{25B6}", style: .plain, target: self, action: #selector(pushGreenVC))
self.navigationItem.rightBarButtonItem = showGreenVC
}
@objc func pushGreenVC() {
let navController = self.navigationController as! NavigationController
navController.pushGreenVC()
}
}
class GreenViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.green
let showRedVC = UIBarButtonItem(title: "\u{25C0} Red", style: .plain, target: self, action: #selector(popGreenVC))
self.navigationItem.leftBarButtonItem = showRedVC
}
@objc func popGreenVC() {
let navController = self.navigationController as! NavigationController
navController.popGreenVC()
}
}
class TitleView: UIView {
let yellowView = UIView()
let blueView = UIView()
convenience init() {
self.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
yellowView.translatesAutoresizingMaskIntoConstraints = false
blueView.translatesAutoresizingMaskIntoConstraints = false
yellowView.backgroundColor = UIColor.yellow
blueView.backgroundColor = UIColor.blue
self.addSubview(yellowView)
self.addSubview(blueView)
yellowView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
yellowView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
yellowView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
yellowView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
blueView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
blueView.leadingAnchor.constraint(equalTo: yellowView.trailingAnchor).isActive = true
blueView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
blueView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
}
func changeTitleViewHeight(to:CGFloat) {
titleViewHeightConstraint.constant = to - view.safeAreaInsets.top
}
override func viewSafeAreaInsetsDidChange() {
let navController = self.navigationController as! NavigationController
navController.changeTitleViewHeight(to: view.safeAreaInsets.top)
}
(3)在其他VCs中,根据需要设置左/右按钮,并根据需要按下/弹出。我喜欢使用UTF-8字符的自定义“箭头”:
var navController: NavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
navController = NavigationController(nibName: nil, bundle: nil)
self.window!.rootViewController = navController
self.window?.makeKeyAndVisible()
return true
}
class NavigationController:UINavigationController {
let redVC = RedViewController()
let greenVC = GreenViewController()
let titleView = TitleView()
var titleViewHeightConstraint:NSLayoutConstraint!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
pushViewController(redVC, animated: false) // display the first VC
}
func popGreenVC() {
popViewController(animated: true)
}
func pushGreenVC() {
pushViewController(greenVC, animated: true)
}
}
class RedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.red
let showGreenVC = UIBarButtonItem(title: "Green \u{25B6}", style: .plain, target: self, action: #selector(pushGreenVC))
self.navigationItem.rightBarButtonItem = showGreenVC
}
@objc func pushGreenVC() {
let navController = self.navigationController as! NavigationController
navController.pushGreenVC()
}
}
class GreenViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.green
let showRedVC = UIBarButtonItem(title: "\u{25C0} Red", style: .plain, target: self, action: #selector(popGreenVC))
self.navigationItem.leftBarButtonItem = showRedVC
}
@objc func popGreenVC() {
let navController = self.navigationController as! NavigationController
navController.popGreenVC()
}
}
class TitleView: UIView {
let yellowView = UIView()
let blueView = UIView()
convenience init() {
self.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
yellowView.translatesAutoresizingMaskIntoConstraints = false
blueView.translatesAutoresizingMaskIntoConstraints = false
yellowView.backgroundColor = UIColor.yellow
blueView.backgroundColor = UIColor.blue
self.addSubview(yellowView)
self.addSubview(blueView)
yellowView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
yellowView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
yellowView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
yellowView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
blueView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
blueView.leadingAnchor.constraint(equalTo: yellowView.trailingAnchor).isActive = true
blueView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
blueView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
}
func changeTitleViewHeight(to:CGFloat) {
titleViewHeightConstraint.constant = to - view.safeAreaInsets.top
}
override func viewSafeAreaInsetsDidChange() {
let navController = self.navigationController as! NavigationController
navController.changeTitleViewHeight(to: view.safeAreaInsets.top)
}
请注意,我强制转换视图的naviagtionController?
属性作为我的子类类型。需要强制转换才能访问其中的自定义方法
(4)下一步,包括您自定义的“标题视图”。为了演示,我创建了一个50/50的黄色/蓝色。请注意,它使用自动布局锚定:
var navController: NavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
navController = NavigationController(nibName: nil, bundle: nil)
self.window!.rootViewController = navController
self.window?.makeKeyAndVisible()
return true
}
class NavigationController:UINavigationController {
let redVC = RedViewController()
let greenVC = GreenViewController()
let titleView = TitleView()
var titleViewHeightConstraint:NSLayoutConstraint!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
pushViewController(redVC, animated: false) // display the first VC
}
func popGreenVC() {
popViewController(animated: true)
}
func pushGreenVC() {
pushViewController(greenVC, animated: true)
}
}
class RedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.red
let showGreenVC = UIBarButtonItem(title: "Green \u{25B6}", style: .plain, target: self, action: #selector(pushGreenVC))
self.navigationItem.rightBarButtonItem = showGreenVC
}
@objc func pushGreenVC() {
let navController = self.navigationController as! NavigationController
navController.pushGreenVC()
}
}
class GreenViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.green
let showRedVC = UIBarButtonItem(title: "\u{25C0} Red", style: .plain, target: self, action: #selector(popGreenVC))
self.navigationItem.leftBarButtonItem = showRedVC
}
@objc func popGreenVC() {
let navController = self.navigationController as! NavigationController
navController.popGreenVC()
}
}
class TitleView: UIView {
let yellowView = UIView()
let blueView = UIView()
convenience init() {
self.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
yellowView.translatesAutoresizingMaskIntoConstraints = false
blueView.translatesAutoresizingMaskIntoConstraints = false
yellowView.backgroundColor = UIColor.yellow
blueView.backgroundColor = UIColor.blue
self.addSubview(yellowView)
self.addSubview(blueView)
yellowView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
yellowView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
yellowView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
yellowView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
blueView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
blueView.leadingAnchor.constraint(equalTo: yellowView.trailingAnchor).isActive = true
blueView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
blueView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
}
func changeTitleViewHeight(to:CGFloat) {
titleViewHeightConstraint.constant = to - view.safeAreaInsets.top
}
override func viewSafeAreaInsetsDidChange() {
let navController = self.navigationController as! NavigationController
navController.changeTitleViewHeight(to: view.safeAreaInsets.top)
}
(5) 在导航控制器的初始化中,添加代码以添加标题视图。请注意,我将自动布局与两个东西一起使用。首先,我将宽度设置为状态栏宽度的1/3。您可以进行实验-对于图像,您最好设置一个恒定的宽度。其次,请注意名为titleViewHeightConstraint
的“命名”约束的用法。我将在下一步解释这一点
titleViewHeightConstraint = titleView.heightAnchor.constraint(equalToConstant: 0)
titleViewHeightConstraint.isActive = true
titleView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
titleView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
titleView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.3).isActive = true
(5)动态调整标题标签的高度:
var navController: NavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
navController = NavigationController(nibName: nil, bundle: nil)
self.window!.rootViewController = navController
self.window?.makeKeyAndVisible()
return true
}
class NavigationController:UINavigationController {
let redVC = RedViewController()
let greenVC = GreenViewController()
let titleView = TitleView()
var titleViewHeightConstraint:NSLayoutConstraint!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
pushViewController(redVC, animated: false) // display the first VC
}
func popGreenVC() {
popViewController(animated: true)
}
func pushGreenVC() {
pushViewController(greenVC, animated: true)
}
}
class RedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.red
let showGreenVC = UIBarButtonItem(title: "Green \u{25B6}", style: .plain, target: self, action: #selector(pushGreenVC))
self.navigationItem.rightBarButtonItem = showGreenVC
}
@objc func pushGreenVC() {
let navController = self.navigationController as! NavigationController
navController.pushGreenVC()
}
}
class GreenViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.green
let showRedVC = UIBarButtonItem(title: "\u{25C0} Red", style: .plain, target: self, action: #selector(popGreenVC))
self.navigationItem.leftBarButtonItem = showRedVC
}
@objc func popGreenVC() {
let navController = self.navigationController as! NavigationController
navController.popGreenVC()
}
}
class TitleView: UIView {
let yellowView = UIView()
let blueView = UIView()
convenience init() {
self.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
yellowView.translatesAutoresizingMaskIntoConstraints = false
blueView.translatesAutoresizingMaskIntoConstraints = false
yellowView.backgroundColor = UIColor.yellow
blueView.backgroundColor = UIColor.blue
self.addSubview(yellowView)
self.addSubview(blueView)
yellowView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
yellowView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
yellowView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
yellowView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
blueView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
blueView.leadingAnchor.constraint(equalTo: yellowView.trailingAnchor).isActive = true
blueView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
blueView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
}
func changeTitleViewHeight(to:CGFloat) {
titleViewHeightConstraint.constant = to - view.safeAreaInsets.top
}
override func viewSafeAreaInsetsDidChange() {
let navController = self.navigationController as! NavigationController
navController.changeTitleViewHeight(to: view.safeAreaInsets.top)
}
请记住,UINavigationController
实际上是一个容器视图控制器。它的“根”视图是全屏的,所以如果你将标题标签锚定到底部,你会得到一个从上到下的垂直大小的标签。更糟糕的是,有时会有一个状态栏,尤其是在肖像中。但其他时候(默认情况下)并非如此。因此,我使用导航控制器(检测是否存在状态栏)和视图控制器(检测导航栏和状态栏的高度)的safeAreaLayoutGuide
(5a)将此方法添加到导航控制器:
var navController: NavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
navController = NavigationController(nibName: nil, bundle: nil)
self.window!.rootViewController = navController
self.window?.makeKeyAndVisible()
return true
}
class NavigationController:UINavigationController {
let redVC = RedViewController()
let greenVC = GreenViewController()
let titleView = TitleView()
var titleViewHeightConstraint:NSLayoutConstraint!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
pushViewController(redVC, animated: false) // display the first VC
}
func popGreenVC() {
popViewController(animated: true)
}
func pushGreenVC() {
pushViewController(greenVC, animated: true)
}
}
class RedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.red
let showGreenVC = UIBarButtonItem(title: "Green \u{25B6}", style: .plain, target: self, action: #selector(pushGreenVC))
self.navigationItem.rightBarButtonItem = showGreenVC
}
@objc func pushGreenVC() {
let navController = self.navigationController as! NavigationController
navController.pushGreenVC()
}
}
class GreenViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.green
let showRedVC = UIBarButtonItem(title: "\u{25C0} Red", style: .plain, target: self, action: #selector(popGreenVC))
self.navigationItem.leftBarButtonItem = showRedVC
}
@objc func popGreenVC() {
let navController = self.navigationController as! NavigationController
navController.popGreenVC()
}
}
class TitleView: UIView {
let yellowView = UIView()
let blueView = UIView()
convenience init() {
self.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
yellowView.translatesAutoresizingMaskIntoConstraints = false
blueView.translatesAutoresizingMaskIntoConstraints = false
yellowView.backgroundColor = UIColor.yellow
blueView.backgroundColor = UIColor.blue
self.addSubview(yellowView)
self.addSubview(blueView)
yellowView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
yellowView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
yellowView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
yellowView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
blueView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
blueView.leadingAnchor.constraint(equalTo: yellowView.trailingAnchor).isActive = true
blueView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
blueView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
}
func changeTitleViewHeight(to:CGFloat) {
titleViewHeightConstraint.constant = to - view.safeAreaInsets.top
}
override func viewSafeAreaInsetsDidChange() {
let navController = self.navigationController as! NavigationController
navController.changeTitleViewHeight(to: view.safeAreaInsets.top)
}
(5b)并将此覆盖添加到子类导航控制器内的所有视图控制器:
var navController: NavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
navController = NavigationController(nibName: nil, bundle: nil)
self.window!.rootViewController = navController
self.window?.makeKeyAndVisible()
return true
}
class NavigationController:UINavigationController {
let redVC = RedViewController()
let greenVC = GreenViewController()
let titleView = TitleView()
var titleViewHeightConstraint:NSLayoutConstraint!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
pushViewController(redVC, animated: false) // display the first VC
}
func popGreenVC() {
popViewController(animated: true)
}
func pushGreenVC() {
pushViewController(greenVC, animated: true)
}
}
class RedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.red
let showGreenVC = UIBarButtonItem(title: "Green \u{25B6}", style: .plain, target: self, action: #selector(pushGreenVC))
self.navigationItem.rightBarButtonItem = showGreenVC
}
@objc func pushGreenVC() {
let navController = self.navigationController as! NavigationController
navController.pushGreenVC()
}
}
class GreenViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.green
let showRedVC = UIBarButtonItem(title: "\u{25C0} Red", style: .plain, target: self, action: #selector(popGreenVC))
self.navigationItem.leftBarButtonItem = showRedVC
}
@objc func popGreenVC() {
let navController = self.navigationController as! NavigationController
navController.popGreenVC()
}
}
class TitleView: UIView {
let yellowView = UIView()
let blueView = UIView()
convenience init() {
self.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
yellowView.translatesAutoresizingMaskIntoConstraints = false
blueView.translatesAutoresizingMaskIntoConstraints = false
yellowView.backgroundColor = UIColor.yellow
blueView.backgroundColor = UIColor.blue
self.addSubview(yellowView)
self.addSubview(blueView)
yellowView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
yellowView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
yellowView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
yellowView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
blueView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
blueView.leadingAnchor.constraint(equalTo: yellowView.trailingAnchor).isActive = true
blueView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
blueView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
}
func changeTitleViewHeight(to:CGFloat) {
titleViewHeightConstraint.constant = to - view.safeAreaInsets.top
}
override func viewSafeAreaInsetsDidChange() {
let navController = self.navigationController as! NavigationController
navController.changeTitleViewHeight(to: view.safeAreaInsets.top)
}
创建自定义“标题标签”的最佳方法是对
UIView
和UINavigationController
进行子类化。这方面的演示是
主要部件包括导航控制器。基本上,您希望将title
属性保留为空(一个空字符串或不设置它),并且由于UINavigationController
只是UIViewController
的一个子类,作为具有push/pop功能的容器视图工作,因此可以以这种方式使用您的子类。在我的演示中,我的子类nav控制器类被称为NavigationController
在我看来,您从子类化UINavigationController
中获得的主要优势是使用它的push/pop功能。。。虽然你可以使用segues,但它们需要一个故事板,虽然你可以使用UIView
动画,但我觉得它并不“流畅”
(1)如果您没有使用情节提要,请记住在AppDelegate
:
var navController: NavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
navController = NavigationController(nibName: nil, bundle: nil)
self.window!.rootViewController = navController
self.window?.makeKeyAndVisible()
return true
}
class NavigationController:UINavigationController {
let redVC = RedViewController()
let greenVC = GreenViewController()
let titleView = TitleView()
var titleViewHeightConstraint:NSLayoutConstraint!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
pushViewController(redVC, animated: false) // display the first VC
}
func popGreenVC() {
popViewController(animated: true)
}
func pushGreenVC() {
pushViewController(greenVC, animated: true)
}
}
class RedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.red
let showGreenVC = UIBarButtonItem(title: "Green \u{25B6}", style: .plain, target: self, action: #selector(pushGreenVC))
self.navigationItem.rightBarButtonItem = showGreenVC
}
@objc func pushGreenVC() {
let navController = self.navigationController as! NavigationController
navController.pushGreenVC()
}
}
class GreenViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.green
let showRedVC = UIBarButtonItem(title: "\u{25C0} Red", style: .plain, target: self, action: #selector(popGreenVC))
self.navigationItem.leftBarButtonItem = showRedVC
}
@objc func popGreenVC() {
let navController = self.navigationController as! NavigationController
navController.popGreenVC()
}
}
class TitleView: UIView {
let yellowView = UIView()
let blueView = UIView()
convenience init() {
self.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
yellowView.translatesAutoresizingMaskIntoConstraints = false
blueView.translatesAutoresizingMaskIntoConstraints = false
yellowView.backgroundColor = UIColor.yellow
blueView.backgroundColor = UIColor.blue
self.addSubview(yellowView)
self.addSubview(blueView)
yellowView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
yellowView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
yellowView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
yellowView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
blueView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
blueView.leadingAnchor.constraint(equalTo: yellowView.trailingAnchor).isActive = true
blueView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
blueView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
}
func changeTitleViewHeight(to:CGFloat) {
titleViewHeightConstraint.constant = to - view.safeAreaInsets.top
}
override func viewSafeAreaInsetsDidChange() {
let navController = self.navigationController as! NavigationController
navController.changeTitleViewHeight(to: view.safeAreaInsets.top)
}
(2)虽然还有其他方法可以做到这一点,但我更喜欢在我的子类中实例化视图控制器,根据需要将方法公开给push/pop:
var navController: NavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
navController = NavigationController(nibName: nil, bundle: nil)
self.window!.rootViewController = navController
self.window?.makeKeyAndVisible()
return true
}
class NavigationController:UINavigationController {
let redVC = RedViewController()
let greenVC = GreenViewController()
let titleView = TitleView()
var titleViewHeightConstraint:NSLayoutConstraint!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
pushViewController(redVC, animated: false) // display the first VC
}
func popGreenVC() {
popViewController(animated: true)
}
func pushGreenVC() {
pushViewController(greenVC, animated: true)
}
}
class RedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.red
let showGreenVC = UIBarButtonItem(title: "Green \u{25B6}", style: .plain, target: self, action: #selector(pushGreenVC))
self.navigationItem.rightBarButtonItem = showGreenVC
}
@objc func pushGreenVC() {
let navController = self.navigationController as! NavigationController
navController.pushGreenVC()
}
}
class GreenViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.green
let showRedVC = UIBarButtonItem(title: "\u{25C0} Red", style: .plain, target: self, action: #selector(popGreenVC))
self.navigationItem.leftBarButtonItem = showRedVC
}
@objc func popGreenVC() {
let navController = self.navigationController as! NavigationController
navController.popGreenVC()
}
}
class TitleView: UIView {
let yellowView = UIView()
let blueView = UIView()
convenience init() {
self.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
yellowView.translatesAutoresizingMaskIntoConstraints = false
blueView.translatesAutoresizingMaskIntoConstraints = false
yellowView.backgroundColor = UIColor.yellow
blueView.backgroundColor = UIColor.blue
self.addSubview(yellowView)
self.addSubview(blueView)
yellowView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
yellowView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
yellowView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
yellowView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
blueView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
blueView.leadingAnchor.constraint(equalTo: yellowView.trailingAnchor).isActive = true
blueView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
blueView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
}
func changeTitleViewHeight(to:CGFloat) {
titleViewHeightConstraint.constant = to - view.safeAreaInsets.top
}
override func viewSafeAreaInsetsDidChange() {
let navController = self.navigationController as! NavigationController
navController.changeTitleViewHeight(to: view.safeAreaInsets.top)
}
(3)在其他VCs中,设置