it-swarm.com.de

UINavigationBar ändert die Farben beim Drücken

Ich verwende 2 verschiedene Balkentönungsfarben bei UINavigationBar in verschiedenen Ansichten. Ich wechsle mit dieser Methode in beiden Ansichten die Farbe:

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

Wenn ich auf die Schaltfläche "Zurück" tippe, ändert sich die Farbe nicht reibungslos (Sie können in der letzten Sekunde ein Blinken sehen).

 Visual bug

Aber alles ist in Ordnung, wenn Sie einfach die Ansicht zurück streichen, anstatt auf die Schaltfläche "Zurück" zu tippen.

 No visual bug

Wie kann in beiden Situationen ein reibungsloser Übergang erfolgen?

18
Vasily

Ich habe eine endgültige Lösung programmiert, die am bequemsten zu verwenden ist (Sie müssen nicht viele Überschreibungen in eigenen View-Controllern verwenden). Es funktioniert perfekt unter iOS 10 und ist für eigene Zwecke einfach anpassbar.

GitHub

Sie können GitHub Gist auf den vollständigen Klassencode und detailliertere Anleitungen überprüfen. Ich werde hier keinen vollständigen Code posten, da Stackoverflow nicht zum Speichern von viel Code vorgesehen ist.

Verwendungszweck

Laden Sie die Swift-Datei für GitHub herunter. Damit dies funktioniert, verwenden Sie einfach ColorableNavigationController anstelle von UINavigationController und übernehmen Sie die erforderlichen untergeordneten View-Controller in das NavigationBarColorable-Protokoll.

Beispiel:

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())
9
Vasily

Um diese Art der Animation zu erreichen, sollten Sie UIViewControllerTransitionCoordinator as Apple-Dokumentation verwenden.

Ein Objekt, das das UIViewControllerTransitionCoordinator-Protokoll verwendet, unterstützt Animationen, die mit einem View Controller-Übergang verknüpft sind. (...)

Also hat jedes UIViewController ein eigenes transitionController. Um dies zu bekommen, sollten Sie das UIViewControllerClass aufrufen:

self.transitionCoordinator()

Von Dokumentation :

Gibt das aktive Übergangskoordinatorobjekt zurück.

Um das gewünschte Ergebnis zu erzielen, müssen Sie die animateAlongsideTransition -Methode in viewController transitionCoordinatior implementieren. Die Animation funktioniert, wenn Sie auf backButton klicken und nach hinten wischen.

Beispiel

navigation_bar_animation

Erster Controller:

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
    }
}

Zweiter Controller:

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) {
        super.viewDidAppear(animated)
        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

In iOS 10 ist es schwierig, den willMoveTo(parentViewController parent: UIViewController?) in den second ViewController einzufügen. Und setzen Sie die Navigationsleiste tintColor auf den Farbwert von previous. Setzen Sie außerdem in der viewDidAppear -Methode in second ViewControler den Wert navigationBar.tintColor Auf Farbe von Sekunde viewController.

Schau dir mein Beispiel an Projekt auf Github

19
kamwysoc

Das hat bei mir funktioniert:

 override func willMove(toParent parent: UIViewController?) {
      super.willMove(toParent: parent)
      navigationController?.navigationBar.barTintColor = previous view controller's navigation bar color
 }
2
sash

Ich wundere mich. Für den gleichen Zweck verwende ich UINavigationControllerDelegate. In navigationController(_:willShow:) starte ich die Animation mit transitionCoordinator?.animate(alongsideTransition:completion:). Es funktioniert hervorragend, wenn Sie neue Controller einsetzen, Pop jedoch nicht. 

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
    }
})

Sehen Sie einen Grund, warum es mit Pushes funktionieren sollte, aber nicht mit Pops?

 Push and pop

0
olejnjak