web-dev-qa-db-fra.com

Comment présenter le contrôleur de vue de droite à gauche dans iOS avec Swift

J'utilise presentViewController pour présenter un nouvel écran 

let dashboardWorkout = DashboardWorkoutViewController()
presentViewController(dashboardWorkout, animated: true, completion: nil)

Cela présente un nouvel écran de bas en haut mais je veux qu’il soit présenté de droite à gauche sans utiliser UINavigationController

J'utilise Xib au lieu du storyboard, alors comment puis-je faire cela?

55
Umair Afzal

Peu importe que vous utilisiez xib ou storyboard. Normalement, la transition de droite à gauche est utilisée lorsque vous poussez un contrôleur de vue dans la variable UINavigiationController du présentateur.

METTRE À JOUR

Ajout de la fonction de minutage kCAMediaTimingFunctionEaseInEaseOut

Exemple de projet avec implémentation de Swift 4 ajoutée à GitHub


Swift 3 & 4.2

let transition = CATransition()
transition.duration = 0.5
transition.type = CATransitionType.Push
transition.subtype = CATransitionSubtype.fromRight
transition.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeInEaseOut)
view.window!.layer.add(transition, forKey: kCATransition)
present(dashboardWorkout, animated: false, completion: nil)


ObjC

CATransition *transition = [[CATransition alloc] init];
transition.duration = 0.5;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[transition setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[self.view.window.layer addAnimation:transition forKey:kCATransition];
[self presentViewController:dashboardWorkout animated:false completion:nil];


Swift 2.x

let transition = CATransition()
transition.duration = 0.5
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromRight
transition.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut)
view.window!.layer.addAnimation(transition, forKey: kCATransition)
presentViewController(dashboardWorkout, animated: false, completion: nil)

On dirait que le paramètre animated dans la méthode presentViewController n'a pas vraiment d'importance dans ce cas de transition personnalisée. Il peut avoir n'importe quelle valeur, soit true ou false.

119
mrvincenzo

Code complet pour présenter/congédier, Swift 3

extension UIViewController {

    func presentDetail(_ viewControllerToPresent: UIViewController) {
        let transition = CATransition()
        transition.duration = 0.25
        transition.type = kCATransitionPush
        transition.subtype = kCATransitionFromRight
        self.view.window!.layer.add(transition, forKey: kCATransition)

        present(viewControllerToPresent, animated: false)
    }

    func dismissDetail() {
        let transition = CATransition()
        transition.duration = 0.25
        transition.type = kCATransitionPush
        transition.subtype = kCATransitionFromLeft
        self.view.window!.layer.add(transition, forKey: kCATransition)

        dismiss(animated: false)
    }
}

Vous pouvez également utiliser Segue personnalisé.

Swift 3

class SegueFromRight: UIStoryboardSegue
{ 
    override func perform()
    {
    let src = self.source
    let dst = self.destination

    src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
    dst.view.transform = CGAffineTransform(translationX: src.view.frame.size.width, y: 0)

    UIView.animate(withDuration: 0.25,
                   delay: 0.0,
                   options: UIViewAnimationOptions.curveEaseInOut,
                   animations: {
                    dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
    },
                   completion: { finished in
                    src.present(dst, animated: false, completion: nil)
    }
    )
}
}
12
Photon Point

Lisez toutes les réponses et ne voyez pas la solution correcte. La bonne façon de le faire est de créer un délégué UIViewControllerAnimatedTransitioning personnalisé pour le délégué VC présenté. 

Donc, cela suppose de faire plus d’étapes, mais le résultat est plus personnalisable et n’a pas certains effets secondaires, comme le fait de quitter une vue avec la vue présentée.

Alors, supposons que vous avez ViewController, et il existe une méthode pour présenter

var presentTransition: UIViewControllerAnimatedTransitioning?
var dismissTransition: UIViewControllerAnimatedTransitioning?    

func showSettings(animated: Bool) {
    let vc = ... create new vc to present

    presentTransition = RightToLeftTransition()
    dismissTransition = LeftToRightTransition()

    vc.modalPresentationStyle = .custom
    vc.transitioningDelegate = self

    present(vc, animated: true, completion: { [weak self] in
        self?.presentTransition = nil
    })
}

presentTransition et dismissTransition sont utilisés pour animer vos contrôleurs de vue. Vous adoptez donc votre ViewController à UIViewControllerTransitioningDelegate:

extension ViewController: UIViewControllerTransitioningDelegate {
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return presentTransition
    }

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return dismissTransition
    }
}

La dernière étape consiste donc à créer votre transition personnalisée:

class RightToLeftTransition: NSObject, UIViewControllerAnimatedTransitioning {
    let duration: TimeInterval = 0.25

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let container = transitionContext.containerView
        let toView = transitionContext.view(forKey: .to)!

        container.addSubview(toView)
        toView.frame.Origin = CGPoint(x: toView.frame.width, y: 0)

        UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: {
            toView.frame.Origin = CGPoint(x: 0, y: 0)
        }, completion: { _ in
            transitionContext.completeTransition(true)
        })
    }
}

class LeftToRightTransition: NSObject, UIViewControllerAnimatedTransitioning {
    let duration: TimeInterval = 0.25

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let container = transitionContext.containerView
        let fromView = transitionContext.view(forKey: .from)!

        container.addSubview(fromView)
        fromView.frame.Origin = .zero

        UIView.animate(withDuration: duration, delay: 0, options: .curveEaseIn, animations: {
            fromView.frame.Origin = CGPoint(x: fromView.frame.width, y: 0)
        }, completion: { _ in
            fromView.removeFromSuperview()
            transitionContext.completeTransition(true)
        })
    }
}

Dans la mesure où ce contrôleur de vue de code est présenté sur le contexte actuel, vous pouvez effectuer vos personnalisations à partir de ce point. Aussi, vous pouvez constater que la personnalisation UIPresentationController est également utile (transmettez-la à l'aide de UIViewControllerTransitioningDelegate)

11
HotJard

Essaye ça,

    let animation = CATransition()
    animation.duration = 0.5
    animation.type = kCATransitionPush
    animation.subtype = kCATransitionFromRight
     animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    vc.view.layer.addAnimation(animation, forKey: "SwitchToView")

    self.presentViewController(vc, animated: false, completion: nil)

Ici vc est viewcontroller, dashboardWorkout dans votre cas.

6
Lion

Si vous souhaitez utiliser la méthode "solution rapide" CATransition ....

class AA: UIViewController

 func goToBB {

    let bb = .. instantiateViewcontroller, storyboard etc .. as! AlreadyOnboardLogin

    let tr = CATransition()
    tr.duration = 0.25
    tr.type = kCATransitionMoveIn // use "MoveIn" here
    tr.subtype = kCATransitionFromRight
    view.window!.layer.add(tr, forKey: kCATransition)

    present(bb, animated: false)
    bb.delegate, etc = set any other needed values
}

et alors ...

func dismissingBB() {

    let tr = CATransition()
    tr.duration = 0.25
    tr.type = kCATransitionReveal // use "Reveal" here
    tr.subtype = kCATransitionFromLeft
    view.window!.layer.add(tr, forKey: kCATransition)

    dismiss(self) .. or dismiss(bb), or whatever
}

Malheureusement, tout cela n’est pas vraiment correct :(

CATransition n'est pas vraiment fait pour faire ce travail.

Notez que vous obtiendrez le fade cross fade to black qui gâche malheureusement l'effet.


De nombreux développeurs (comme moi) n'aiment vraiment pas utiliser NavigationController. Souvent, il est plus flexible de présenter de manière ad hoc au fur et à mesure, en particulier pour les applications inhabituelles et complexes. Cependant, il n’est pas difficile d’ajouter un contrôleur de navigation.

  1. simplement sur le storyboard, allez à l’entrée VC et cliquez sur "intégrer -> dans le contrôleur de navigation". Vraiment c'est ça. Ou,

  2. dans didFinishLaunchingWithOptions il est facile de construire votre contrôleur de navigation si vous préférez

  3. vous n'avez même pas besoin de conserver la variable où que vous soyez, car .navigationController est toujours disponible en tant que propriété - c'est facile.

Vraiment, une fois que vous avez un navigateurContrôleur, il est facile de faire des transitions entre les écrans,

    let nextScreen = instantiateViewController etc as! NextScreen
    navigationController?
        .pushViewController(nextScreen, animated: true)

et vous pouvez pop.

Cela ne vous donne toutefois que l'effet "double push" standard d'Apple ...

(L'ancien glisse moins vite que le nouveau glisse.)

De manière générale et surprenante, vous devez généralement vous efforcer de réaliser une transition personnalisée complète.

Même si vous voulez juste la transition la plus simple, la plus courante, le transfert/le déplacement, vous devez effectuer une transition personnalisée complète.

Heureusement, pour ce faire, il y a du copier/coller du code standard sur ce QA ... https://stackoverflow.com/a/48081504/294884 . Bonne année 2018!

4
Fattie

Essaye ça.

let transition: CATransition = CATransition()
transition.duration = 0.3

transition.type = kCATransitionReveal
transition.subtype = kCATransitionFromLeft
self.view.window!.layer.addAnimation(transition, forKey: nil)
self.dismissViewControllerAnimated(false, completion: nil)
1
Ashwin Felix

présent contrôleur de vue de droite à gauche dans iOS avec Swift

func FrkTransition() 

{
    let transition = CATransition()

    transition.duration = 2

    transition.type = kCATransitionPush

    transitioningLayer.add(transition,forKey: "transition")

    // Transition to "blue" state

    transitioningLayer.backgroundColor = UIColor.blue.cgColor
    transitioningLayer.string = "Blue"
}

Refrence By: [ https://developer.Apple.com/documentation/quartzcore/catransition][1]

0
FURKAN VIJAPURA

importer UIKit et créer une extension pour UIViewController:

extension UIViewController {
func transitionVc(vc: UIViewController, duration: CFTimeInterval, type: CATransitionSubtype) {
    let customVcTransition = vc
    let transition = CATransition()
    transition.duration = duration
    transition.type = CATransitionType.Push
    transition.subtype = type
    transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    view.window!.layer.add(transition, forKey: kCATransition)
    present(customVcTransition, animated: false, completion: nil)
}}

après appel simlpy:

let vC = YourViewController()
transitionVc(vc: vC, duration: 0.5, type: .fromRight)

de gauche à droite:

let vC = YourViewController()
transitionVc(vc: vC, duration: 0.5, type: .fromleft)

vous pouvez changer la durée avec votre durée préférée ...

0
Fabio
let transition = CATransition()
    transition.duration = 0.25
    transition.type = kCATransitionPush
    transition.subtype = kCATransitionFromLeft
    transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
    tabBarController?.view.layer.add(transition, forKey: kCATransition)
    self.navigationController?.popToRootViewController(animated: true)
0
Chilli