Подтвердить что ты не робот

Как изменить/изменить цвет 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. Это невозможно?

4b9b3361

Ответ 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)
    }
}

Примечание. Координация цветовой анимации выполняется с помощью навигационного контроллера