Лучший способ создать собственную "titleLabel" - это создать подклассы UIView
и UINavigationController
.Демонстрация этого: здесь .
Основные части с контроллером навигации.По сути, вы хотите оставить свойство title
пустым (пустая строка или просто не устанавливать его), и, поскольку UINavigationController
является просто подклассом UIViewController
, работающим как контейнерное представление с возможностями push / pop, работайтес вашим подклассом таким образом.В моей демонстрации мой подклассный класс контроллера навигации называется NavigationController
.
На мой взгляд, главное преимущество, которое вы получаете от создания подкласса UINavigationController
, - это , использующее возможности push / pop ..... в то время как вы можете использовать сегменты, они требуют раскадровки, и в то время как вы можете использовать анимацию 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
}
(2) Хотя есть другие способы сделать это, мойпредпочтение отдается созданию экземпляров контроллеров представления в моем подклассе, предоставляя при необходимости методы push / pop:
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)
}
}
(3) В других VC установите ваши кнопки влево / вправо какнужно и нажмите / поп по мере необходимости.Мне нравится пользовательская «стрелка» с использованием символов UTF-8:
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()
}
}
Обратите внимание, что я принудительно приводю свойство представления naviagtionController?
в качестве моего подкласса.Приведение необходимо, чтобы получить доступ к пользовательским методам в нем.
(4) Далее, включите ваш собственный "titleView".Для демонстрации я создал 50/50 желто-синий.Обратите внимание, что он использует якоря автоматического макета:
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
}
}
(5) В init контроллера Nav добавьте код, чтобы добавить вид заголовка.Обратите внимание, что я использую автоматическую разметку с двумя вещами.Во-первых, я устанавливаю ширину равной 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) Сделайте высоту вашей метки заголовка динамической:
Помните, что UINavigationController
- этона самом деле контроллер представления контейнера - это все аспекты.Это «корневое» представление в полноэкранном режиме, поэтому, если вы прикрепите метку заголовка к нижней части, вы получите метку вертикального размера сверху вниз.Хуже того, иногда есть строка состояния, особенно если она портретная.Но в других случаях (по умолчанию) это не так.По той причине, что я использую safeAreaLayoutGuide
из и навигационный контроллер (который обнаруживает наличие строки состояния) и контроллеры вида внутри него (который определяет высотупанель навигации ПЛЮС строка состояния).
(5a) Добавьте этот метод к контроллеру навигации:
func changeTitleViewHeight(to:CGFloat) {
titleViewHeightConstraint.constant = to - view.safeAreaInsets.top
}
(5b) и добавьте это переопределениедля всех контроллеров представления внутри субклассированного навигационного контроллера:
override func viewSafeAreaInsetsDidChange() {
let navController = self.navigationController as! NavigationController
navController.changeTitleViewHeight(to: view.safeAreaInsets.top)
}