Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何在Swift中实现自定义NavigationController_Ios_Swift_Uinavigationcontroller_User Profile - Fatal编程技术网

Ios 如何在Swift中实现自定义NavigationController

Ios 如何在Swift中实现自定义NavigationController,ios,swift,uinavigationcontroller,user-profile,Ios,Swift,Uinavigationcontroller,User Profile,我有一个应用程序,它使用NavigationController和TabBarController在不同的视图中轻松导航。对于某些视图,我有一个标题和一些按钮(有时只在右侧,有时在右侧和左侧)。但是,对于某些视图,例如在观看某人的个人资料时,我不想设置标题。我想显示个人资料图片,并在图片下方添加用户名 我的问题很简单:我是否应该使用NavigationController来实现这一点,因为我希望配置文件图片“覆盖”NavigationController,使其与状态栏的距离仅为16像素,而不是与

我有一个应用程序,它使用NavigationController和TabBarController在不同的视图中轻松导航。对于某些视图,我有一个标题和一些按钮(有时只在右侧,有时在右侧和左侧)。但是,对于某些视图,例如在观看某人的个人资料时,我不想设置标题。我想显示个人资料图片,并在图片下方添加用户名

我的问题很简单:我是否应该使用NavigationController来实现这一点,因为我希望配置文件图片“覆盖”NavigationController,使其与状态栏的距离仅为16像素,而不是与NavigationController的距离。在仍然有左键和右键的情况下,这是可能的(例如,编辑您自己的配置文件,或者编辑“更多选项”按钮)

我一直在考虑使用一种完全不同的方法,不使用NavigationController,而是在必要时使用标签来显示标题,并在左侧和右侧添加视图,以便在必要时添加按钮

由于这是我第一次做这样的事情,我很想听听你对如何实现这一结果以及最佳实践的看法。有些事情告诉我,最好使用NavigationController,因为这就是它的目的,但是我如何实现可选标题并在需要时检查它呢?我已经知道如何去除底部发际线以及如何相应地设置背景色,所以这不是最大的问题。我只关心如何在NavigationController上显示图像


谢谢大家

创建自定义“标题标签”的最佳方法是对
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中,设置