33 votes

Comment faire évoluer/animer la couleur de UINavigationBar ?

J'ai cherché à savoir comment faire la transition/animer les barTintColor d'un UINavigationBar depuis un moment maintenant, et je ne vois que des réponses différentes. Certains utilisent UIView.animateWithDuration quelques utilisations CATransition mais les plus intéressants, comme celui-ci utiliser animate(alongsideTransition animation.. J'aime bien le son, mais je n'arrive pas à le faire fonctionner correctement. Est-ce que je fais quelque chose de mal ?

Beaucoup précisent que je peux simplement utiliser le transitionCoordinator sur viewWillAppear: . J'ai mis en place un nouveau super petit projet comme celui-ci :

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

Avec ce code, cela se produit : First

  • La poussée-transition de First à Second semble parfait. Tous les éléments effectuent une transition parfaite, sauf peut-être la barre d'état, qui devient instantanément blanche. Je préférerais savoir comment effectuer la transition, mais je l'accepte pour l'instant.
  • La transition pop de Second à First est complètement faux. Ça empêche les couleurs de Second jusqu'à ce que la transition soit complètement terminée.
  • La transition de la traînée de Second à First a l'air bien, quand on le fait glisser jusqu'en haut. Encore une fois, la barre d'état devient instantanément noire dès que je commence à glisser, mais je ne sais pas si cela peut être corrigé.
  • La transition de la traînée de Second à First mais annulé à mi-chemin et retourné à Second est complètement foutu. Ça a l'air bien jusqu'à ce que Second a repris le contrôle, puis se transforme soudainement en First -couleurs. Cela ne devrait pas se produire.

J'ai fait quelques changements dans mon RootViewController pour le rendre un peu meilleur. J'ai enlevé viewWillAppear: complètement, et l'a changé avec ceci :

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

Avec ce code mis à jour, j'obtiens ceci : Second

Quelques observations :

  • Le passage de First à Second est le même
  • La transition pop de Second à First s'anime maintenant correctement, à l'exception de la flèche arrière, du texte arrière (et de la barre d'état, mais oui ). Ceux-ci sont instantanément changés en noir. Dans le premier gif, vous pouvez voir que la flèche arrière et le texte arrière ont également fait la transition.
  • La transition de la traînée de Second à First a également ce problème, la flèche arrière et le texte arrière sont soudainement noirs au démarrage. La teinte de la barre a été corrigée afin qu'elle n'obtienne pas la mauvaise couleur lors de l'annulation du déplacement.

Qu'est-ce que je fais de mal ? Comment dois-je m'y prendre ?

Ce que je veux, c'est une transition en douceur de tous les éléments. La teinte du bouton arrière, le texte arrière, le titre, la teinte de la barre et la barre d'état. Cela n'est-il pas possible ?

0 votes

Cela fait des mois que je cherche une solution à ce problème.

0 votes

11voto

Josshad Points 686

enter image description here

dans 10 iOS il fonctionne imparfaitement :(

Sous-classez votre contrôleur de navigation pour utiliser le statusbarstyle du contrôleur de vue visible :

class MyNavigationController: UINavigationController {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return visibleViewController!.preferredStatusBarStyle
    }
}

Remplacer preferredStatusBarStyle dans le contrôleur racine et ajouter une fonction pour définir les styles. avant l'animation pop :

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
}

Dans le premier contrôleur :

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
}

En deuxième position :

  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
    }

Exemple de projet : https://github.com/josshad/TestNavBarTransition

2 votes

Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien à titre de référence. Les réponses fournies uniquement par un lien peuvent devenir invalides si l'autre question/réponse est supprimée à l'avenir.

2voto

clemens Points 10221

Vous pouvez écraser les méthodes push et pop de l'application UINavigationController pour définir la couleur de la barre. J'ai stocké la couleur de la barre correspondant à un contrôleur de vue dans son élément de navigation avec une sous-classe personnalisée de UINavigationItem . Le code suivant fonctionne pour moi dans iOS 11 pour les transitions complètes et pour les transitions interactives également :

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

Remarque : La coordination de l'animation des couleurs est assurée par le contrôleur de navigation.

0 votes

Est-ce que cela gère la couleur du titre et de la barre d'état ?

0 votes

Cela a marché pour moi pour les deux, mais vous devriez essayer vous-même.

0 votes

J'ai testé cela et il semble que cela ne couvre pas le cas où vous utilisez le geste de pop interactif pour glisser vers l'arrière, puis changez d'avis et annulez le geste -- dans ce cas, il définit la couleur du contrôleur de vue qui aurait été pop si vous n'aviez pas annulé le geste.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X