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

UINavigationBar меняет цвета при нажатии

Я использую 2 разных цвета оттенков цвета в UINavigationBar в разных представлениях. Я изменяю цвет с этим методом в обоих представлениях:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.navigationBar.barTintColor = COLOR
}

Когда я нажимаю кнопку "Назад", цвет кнопки не изменяется плавно (вы можете видеть мигание в последнюю секунду).

Визуальная ошибка

Но все в порядке, если просто проведите пальцем по экрану назад, а не нажмите на кнопку "Назад".

Нет визуальной ошибки

Как сделать плавный переход в обеих ситуациях?

4b9b3361

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