Как изменить/изменить цвет UINavigationBar?
Я искал, как перевести/анимировать barTintColor
of UINavigationBar
на некоторое время, и я вижу только разные ответы. Некоторые используют UIView.animateWithDuration
, некоторые используют CATransition
, но самые интересные, такие как этот, используют animate(alongsideTransition animation..
, что мне нравится звук, но я могу "Правильно ли он работает. Я что-то делаю неправильно?
Многие указывают, что я могу просто использовать transitionCoordinator
в viewWillAppear:
. Я создал новый супер-крошечный проект, подобный этому:
class RootViewController:UIViewController{ //Only subclassed
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
self?.setNavigationColors()
}, completion: nil)
}
func setNavigationColors(){
//Override in subclasses
}
}
class FirstViewController: RootViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "First"
}
override func setNavigationColors(){
navigationController?.navigationBar.barTintColor = UIColor.white
navigationController?.navigationBar.tintColor = UIColor.black
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.black]
navigationController?.navigationBar.barStyle = UIBarStyle.default
}
}
class SecondViewController: RootViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Second"
}
override func setNavigationColors(){
navigationController?.navigationBar.barTintColor = UIColor.black
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
navigationController?.navigationBar.barStyle = UIBarStyle.black
}
}
С помощью этого кода это происходит:
![First]()
- Нажатие-переход от
First
до Second
выглядит идеально. Все элементы прекрасно перемещаются, возможно, кроме StatusBar, который мгновенно меняется на белый. Я бы предпочел, как его перевести, но сейчас я соглашусь.
- Поп-переход от
Second
до First
полностью неправильный. Он сохраняет цвета от Second
до полного завершения перехода.
- Перемещение по переходу от
Second
до First
выглядит хорошо, когда перетаскивается весь путь. Опять же, StatusBar мгновенно становится черным, как только я начинаю перетаскивать, но я не знаю, можно ли это исправить.
- Переход от
Second
до First
, но отмененный средний перетаскивание и возврат в Second
полностью завинчивается. Он отлично выглядит до тех пор, пока Second
не будет полностью обратно в управление, а затем он внезапно изменится на First
-colors. Этого не должно быть.
Я сделал несколько изменений в моем RootViewController
, чтобы сделать его немного лучше. Я полностью удалил viewWillAppear:
и изменил его следующим образом:
class RootViewController:UIViewController{
override func willMove(toParentViewController parent: UIViewController?) {
if let last = self.navigationController?.viewControllers.last as? RootViewController{
if last == self && self.navigationController!.viewControllers.count > 1{
if let parent = self.navigationController!.viewControllers[self.navigationController!.viewControllers.count - 2] as? RootViewController{
parent.setNavigationColors()
}
}
}
}
override func viewWillDisappear(_ animated: Bool) {
if let parent = navigationController?.viewControllers.last as? RootViewController{
parent.animateNavigationColors()
}
}
override func viewDidAppear(_ animated: Bool) {
self.setNavigationColors()
}
func animateNavigationColors(){
transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
self?.setNavigationColors()
}, completion: nil)
}
func setNavigationColors(){
//Override in subclasses
}
}
С помощью этого обновленного кода я получаю следующее:
![Second]()
Несколько наблюдений:
- Переход от
First
в Second
является тем же самым
- Поп-переход от
Second
до First
теперь анимируется правильно, кроме как со спины-стрелки, обратно-текста (и statusBar, но да..). Они мгновенно меняются на черный. В первом gif вы могли видеть, что обратная стрелка и обратный текст также перешли.
- У перетаскивания с
Second
на First
также есть эта проблема, обратная стрелка и обратный текст внезапно становятся черными при запуске. Фиксированный штрих-код фиксируется так, что при отмене перетаскивания он не получает неправильный цвет.
Что я делаю неправильно? Как я должен это делать?
Я хочу преобразовать все элементы плавно. Оттенок задней кнопки, обратный текст, заголовок, штрих-код и статусBar. Это невозможно?
Ответы
Ответ 1
![введите описание изображения здесь]()
в 10 iOS работает несовершенно: (
Подкласс вашего контроллера навигации, чтобы использовать statusbarstyle видимого контроллера вида:
class MyNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return visibleViewController!.preferredStatusBarStyle
}
}
Переопределите preferredStatusBarStyle в корневом контроллере и добавьте функцию для установки стилей перед поп-анимацией:
private var _preferredStyle = UIStatusBarStyle.default;
override var preferredStatusBarStyle: UIStatusBarStyle {
get {
return _preferredStyle
}
set {
_preferredStyle = newValue
self.setNeedsStatusBarAppearanceUpdate()
}
}
func animateNavigationColors(){
self.setBeforePopNavigationColors()
transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
self?.setNavigationColors()
}, completion: nil)
}
func setBeforePopNavigationColors() {
//Override in subclasses
}
В первом контроллере:
override func setBeforePopNavigationColors() {
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
self.preferredStatusBarStyle = UIStatusBarStyle.lightContent
}
override func setNavigationColors(){
navigationController?.navigationBar.barTintColor = UIColor.white
navigationController?.navigationBar.tintColor = UIColor.black
navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black]
navigationController?.navigationBar.barStyle = UIBarStyle.default
self.preferredStatusBarStyle = UIStatusBarStyle.default
}
Во втором:
override func setNavigationColors(){
navigationController?.navigationBar.barTintColor = UIColor.black
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
navigationController?.navigationBar.barStyle = UIBarStyle.black
self.preferredStatusBarStyle = UIStatusBarStyle.lightContent
}
Пример проекта: https://github.com/josshad/TestNavBarTransition
Ответ 2
Вы можете перезаписать методы push и pop UINavigationController
, чтобы установить цвет панели. Я сохранил цвет бара, соответствующий контроллеру вида в своем навигационном элементе, с пользовательским подклассом UINavigationItem
. Следующий код работает для меня в iOS 11 для полного и для интерактивных переходов:
import UIKit
class NavigationItem: UINavigationItem {
@IBInspectable public var barTintColor: UIColor?
}
class NavigationController: UINavigationController, UIGestureRecognizerDelegate {
func applyTint(_ navigationItem: UINavigationItem?) {
if let item = navigationItem as? NavigationItem {
self.navigationBar.barTintColor = item.barTintColor
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
applyTint(self.topViewController?.navigationItem)
self.interactivePopGestureRecognizer?.delegate = self
}
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
applyTint(viewController.navigationItem)
super.pushViewController(viewController, animated: animated)
}
override func popViewController(animated: Bool) -> UIViewController? {
let viewController = super.popViewController(animated: animated)
applyTint(self.topViewController?.navigationItem)
return viewController
}
override func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? {
let result = super.popToViewController(viewController, animated: animated)
applyTint(viewController.navigationItem)
return result
}
override func popToRootViewController(animated: Bool) -> [UIViewController]? {
let result = super.popToRootViewController(animated: animated)
applyTint(self.topViewController?.navigationItem)
return result
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return (otherGestureRecognizer is UIScreenEdgePanGestureRecognizer)
}
}
Примечание. Координация цветовой анимации выполняется с помощью навигационного контроллера