UINavigationBar меняет цвета при нажатии
Я использую 2 разных цвета оттенков цвета в UINavigationBar
в разных представлениях. Я изменяю цвет с этим методом в обоих представлениях:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.barTintColor = COLOR
}
Когда я нажимаю кнопку "Назад", цвет кнопки не изменяется плавно (вы можете видеть мигание в последнюю секунду).
![Визуальная ошибка]()
Но все в порядке, если просто проведите пальцем по экрану назад, а не нажмите на кнопку "Назад".
![Нет визуальной ошибки]()
Как сделать плавный переход в обеих ситуациях?
Ответы
Ответ 1
Я закодировал окончательное решение, которое выглядит наиболее удобным для использования (не нужно использовать много переопределений в собственных контроллерах представлений). Он отлично работает на iOS 10 и легко адаптируется для собственных целей.
GitHub
Вы можете проверить GitHub Gist для полного кода класса и более подробного руководства, я не буду публиковать полный код здесь, поскольку Stackoverflow не предназначен для хранения большого количества кода.
Использование
Загрузите файл Swift для GitHub. Чтобы заставить его работать, используйте ColorableNavigationController
вместо UINavigationController
и применяйте необходимые контроллеры дочерних представлений к протоколу NavigationBarColorable
.
Пример:
class ViewControllerA: UIViewController, NavigationBarColorable {
public var navigationBarTintColor: UIColor? { return UIColor.blue }
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Push", style: .plain, target: self, action: #selector(self.showController))
}
func showController() {
navigationController?.pushViewController(ViewControllerB(), animated: true)
}
}
class ViewControllerB: UIViewController, NavigationBarColorable {
public var navigationBarTintColor: UIColor? { return UIColor.red }
}
let navigationController = ColorableNavigationController(rootViewController: ViewControllerA())
Ответ 2
Чтобы достичь такой анимации, вы должны использовать UIViewControllerTransitionCoordinator
как документацию Apple:
Объект, который использует протокол UIViewControllerTransitionCoordinator, поддерживает анимацию, связанную с переходом контроллера. (...)
Таким образом, каждый UIViewController
имеет собственный transitionController
. Чтобы получить это, вы должны позвонить в UIViewControllerClass
:
self.transitionCoordinator()
Из документация:
Возвращает активный объект координатора перехода.
Итак, чтобы получить результат, который вы хотите, вы должны реализовать метод animateAlongsideTransition
в viewController transitionCoordinatior. Анимация работает, когда вы нажимаете backButton
и проведите пальцем по экрану назад.
Пример:
![navigation_bar_animation]()
Первый контроллер:
class ViewControllerA: UIViewController {
override func loadView() {
super.loadView()
title = "A"
view.backgroundColor = .white
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "NEXT", style: .plain, target: self, action: #selector(self.showController))
setColors()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
animate()
}
func showController() {
navigationController?.pushViewController(ViewControllerB(), animated: true)
}
private func animate() {
guard let coordinator = self.transitionCoordinator else {
return
}
coordinator.animate(alongsideTransition: {
[weak self] context in
self?.setColors()
}, completion: nil)
}
private func setColors() {
navigationController?.navigationBar.tintColor = .black
navigationController?.navigationBar.barTintColor = .red
}
}
Второй контроллер:
class ViewControllerB : UIViewController {
override func loadView() {
super.loadView()
title = "B"
view.backgroundColor = .white
setColors()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
animate()
}
override func willMove(toParentViewController parent: UIViewController?) { // tricky part in iOS 10
navigationController?.navigationBar.barTintColor = .red //previous color
super.willMove(toParentViewController: parent)
}
override func viewDidAppear(_ animated: Bool) {
navigationController?.navigationBar.barTintColor = .blue
}
private func animate() {
guard let coordinator = self.transitionCoordinator else {
return
}
coordinator.animate(alongsideTransition: {
[weak self] context in
self?.setColors()
}, completion: nil)
}
private func setColors(){
navigationController?.navigationBar.tintColor = .black
navigationController?.navigationBar.barTintColor = .blue
}
}
UPDATE iOS 10
В iOS 10 сложная часть состоит в том, чтобы добавить willMoveTo(parentViewController parent: UIViewController?)
в второй ViewController. И установите для navigationBar tintColor
значение цвета предыдущего. Кроме того, в viewDidAppear
методе в секунду ViewControler установите navigationBar.tintColor
в цвет от второго viewController.
Посмотрите мой пример проект на github
Ответ 3
Мне просто интересно. Для этой же цели я использую UINavigationControllerDelegate
. В navigationController(_:willShow:)
я запускаю анимацию с помощью transitionCoordinator?.animate(alongsideTransition:completion:)
. Он отлично работает при нажатии новых контроллеров, однако поп нет.
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
let dst = viewController as! ViewController
guard animated else {
navigationController.navigationBar.barTintColor = dst.navigationBarColor
navigationController.navigationBar.tintColor = dst.tintColor
navigationController.navigationBar.barStyle = dst.barStyle
return
}
navigationController.transitionCoordinator?.animate(alongsideTransition: { context in
navigationController.navigationBar.barTintColor = dst.navigationBarColor
navigationController.navigationBar.tintColor = dst.tintColor
navigationController.navigationBar.barStyle = dst.barStyle
}, completion: { context in
if context.isCancelled {
let source = context.viewController(forKey: UITransitionContextViewControllerKey.from) as! ViewController
navigationController.navigationBar.barTintColor = source.navigationBarColor
navigationController.navigationBar.tintColor = source.tintColor
navigationController.navigationBar.barStyle = source.barStyle
}
})
Вы видите какую-либо причину, по которой он должен работать с нажатием, но не попсом?
![push and pop]()