web-dev-qa-db-fra.com

Animation de diapositive ViewController

Je veux créer une animation comme l'application Facebook iOS sur tabswitch [1]. J'ai déjà essayé de développer une sorte d'animation, le problème qui se produit est que l'ancien contrôleur de vue devient invisible directement sur le commutateur, au lieu de disparaître lentement pendant que le nouveau contrôleur glisse rapidement.

J'ai trouvé cette SO question Comment animer le changement d'onglet de la barre d'onglets avec une transition de diapositive CrossDissolve? mais la solution marquée comme correcte ne fonctionne pas vraiment pour moi (elle ce n'est pas une diapositive, c'est une transition en fondu.) Ce que j'aimerais aussi, c'est la fonction de faire glisser la gauche ou la droite pour changer les onglets. Comme c'était sur une ancienne version de Facebook.

Ce que j'ai jusqu'à présent, c'est ceci:

extension TabBarController: UITabBarControllerDelegate  {
    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        guard let fromView = selectedViewController?.view,
              let toView = viewController.view else { return false }
        if fromView != toView {
            toView.transform = CGAffineTransform(translationX: -90, y: 0)
            UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut, animations: {
                toView.transform = CGAffineTransform(translationX: 0, y: 0)
            })
        }; return true
    }
}

class TabBarController: UITabBarController {
    override func viewDidLoad() {
        super.viewDidLoad()
        delegate = self
    }
}

Comment résoudre ce problème?


[1] J'aimerais beaucoup ajouter un gif de l'application Facebook. Le problème est que je ne veux pas censurer la vidéo et révéler juste trop de mes données. (Même si fb les a déjà). Aussi sur YouTube, je n'ai pas trouvé d'enregistrement approprié. Veuillez l'essayer vous-même dans l'application fb sur iOS.

10
user3596335

Vous pouvez utiliser l'idée suivante: https://samwize.com/2016/04/27/making-tab-bar-slide-when-selected/

En outre, voici le code mis à jour à Swift 4.1 et j'ai également supprimé les déballages de force:

import UIKit

class MyTabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()

        delegate = self
    }
}

extension MyTabBarController: UITabBarControllerDelegate  {
    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        guard let tabViewControllers = tabBarController.viewControllers, let toIndex = tabViewControllers.index(of: viewController) else {
            return false
        }
        animateToTab(toIndex: toIndex)
        return true
    }

    func animateToTab(toIndex: Int) {
        guard let tabViewControllers = viewControllers,
            let selectedVC = selectedViewController else { return }

        guard let fromView = selectedVC.view,
            let toView = tabViewControllers[toIndex].view,
            let fromIndex = tabViewControllers.index(of: selectedVC),
            fromIndex != toIndex else { return }


        // Add the toView to the tab bar view
        fromView.superview?.addSubview(toView)

        // Position toView off screen (to the left/right of fromView)
        let screenWidth = UIScreen.main.bounds.size.width
        let scrollRight = toIndex > fromIndex
        let offset = (scrollRight ? screenWidth : -screenWidth)
        toView.center = CGPoint(x: fromView.center.x + offset, y: toView.center.y)

        // Disable interaction during animation
        view.isUserInteractionEnabled = false

        UIView.animate(withDuration: 0.3,
                       delay: 0.0,
                       usingSpringWithDamping: 1,
                       initialSpringVelocity: 0,
                       options: .curveEaseOut,
                       animations: {
                        // Slide the views by -offset
                        fromView.center = CGPoint(x: fromView.center.x - offset, y: fromView.center.y)
                        toView.center = CGPoint(x: toView.center.x - offset, y: toView.center.y)

        }, completion: { finished in
            // Remove the old view from the tabbar view.
            fromView.removeFromSuperview()
            self.selectedIndex = toIndex
            self.view.isUserInteractionEnabled = true
        })
    }
}

Donc, vous devez sous-classer UITabBarController et vous devez également écrire la partie d'animation, vous pouvez modifier les options d'animation (délai, durée, etc.).

J'espère que ça aide, bravo!

enter image description here

5
Mihai Erős

Je n'ai jamais vu Facebook, donc je ne sais pas ce qu'est l'animation. Mais vous pouvez avoir toute animation que vous aimez quand un contrôleur de barre d'onglets change son onglet (contrôleur de vue enfant), de manière cohérente et sans aucun piratage, en utilisant le mécanisme intégré qui Apple permet d'ajouter une animation personnalisée à une transition entre les contrôleurs de vue. Cela s'appelle animation de transition personnalisée .

Apple a introduit ce mécanisme pour la première fois en 2013. Voici un lien vers leur vidéo à ce sujet: https://developer.Apple.com/videos/play/wwdc2013/218/

J'ai immédiatement adopté cela dans mes applications, et je pense que cela les rend beaucoup plus épatantes. Voici une démo d'une transition personnalisée de contrôleur de barre d'onglets que j'aime:

enter image description here

Ce qui est vraiment cool, c'est qu'une fois que vous avez décidé quelle animation vous voulez, ce qui rend la transition interactive (c'est-à-dire la piloter avec un geste au lieu d'un clic de bouton) ) est facile:

enter image description here

Maintenant, vous pourriez dire: D'accord, mais ce n'est pas tout à fait l'animation que j'avais en tête. Aucun problème! Une fois que vous avez maîtrisé l'architecture de transition personnalisée, il est facile de changer l'animation pour ce que vous voulez. Dans cette variante, je viens de commenter une ligne pour que le "vieux" contrôleur de vue ne glisse pas:

enter image description here

Alors laissez libre cours à votre imagination! Adoptez des animations de transition personnalisées, comme le prévoit iOS.

7
matt

Si vous voulez quelque chose pour la navigation pushViewController, vous pouvez essayer ceci.

Cependant, lorsque vous basculez entre les onglets d'un TabBarController, cela ne fonctionnera pas. Pour cela, j'irais avec la solution de @ mihai-erős

Modifiez la durée de l'animation selon vos préférences et affectez cette classe à vos séquences de navigation pour une animation de diapositive.

class CustomPushSegue: UIStoryboardSegue {

    override func perform() {
        // first get the source and destination view controllers as UIviews so that they can placed in navigation stack

        let sourceVCView = self.source.view as UIView!
        let destinationVCView = self.destination.view as UIView!
        let screenWidth = UIScreen.main.bounds.size.width

        //create the destination view's rectangular frame i.e starting at 0,0 and equal to screenwidth by screenheight
        destinationVCView?.transform = CGAffineTransform(translationX: screenWidth, y: 0)

        //the destinationview needs to be placed on top(aboveSubView) of source view in the app window stack before being accessed by nav stack
        // get the window and insert destination View
        let window = UIApplication.shared.keyWindow
        window?.insertSubview(destinationVCView!, aboveSubview: sourceVCView!)


        // the animation: first remove the source out of screen by moving it at the left side of it and at the same time place the destination to source's position
        // Animate the transition.
        UIView.animate(withDuration: 0.3, animations: { () -> Void in
            sourceVCView?.transform = CGAffineTransform(translationX: -screenWidth,y: 0)
            destinationVCView?.transform = CGAffineTransform.identity

        }, completion: { (Finished) -> Void in
            self.source.present(self.destination, animated: false, completion: nil)
        }) 
    }
}
2
Kinshuk Kashyap