Come modificare le animazioni Push e Pop in un'app basata sulla navigazione


221

Ho un'applicazione basata sulla navigazione e voglio cambiare l'animazione delle animazioni push e pop. Come potrei farlo?

Modifica 2018

Ci sono state molte risposte a questa domanda ed è passato un bel po 'di tempo, ho rieletto la risposta a ciò che ritengo essere il più rilevante ora. Se c'è qualcuno che la pensa diversamente, fatemelo sapere nei commenti


25
A partire da iOS 7, esiste un'API ufficiale per questo; vedere il supporto per l'animazione della transizione personalizzata di UINavigationControllerDelegate . C'è anche un video del WWDC 2013 su questo.
Jesse Rusak,

Ho aggiunto una risposta (sotto) per farlo in Swift: mi sono imbattuto in questa domanda che mi chiedeva delle implementazioni di Swift, quindi ho pensato di entrare in contatto con la mia successiva implementazione.
DJJP

1
Per un ottimo tutorial con l'API ufficiale (iOS 7+), vedere: bradbambara.wordpress.com/2014/04/11/…
nikolovski

1
@JesseRusak collegamento aggiornato al WWDC 2013 Video: developer.apple.com/videos/play/wwdc2013-218
Wojciech Rutkowski

1
Modificata la mia risposta accettata, ragazzi e ragazze. Spero che questo ti aiuti! GLHF
Jab

Risposte:


35

Come modificare le animazioni Push e Pop in un'app basata sulla navigazione ...

Per il 2019, la "risposta finale!"

Preambolo:

Supponi di essere nuovo nello sviluppo di iOS. In modo confuso, Apple fornisce due transizioni che possono essere utilizzate facilmente. Questi sono: "crossfade" e "flip".

Ma, naturalmente, "crossfade" e "flip" sono inutili. Non vengono mai usati. Nessuno sa perché Apple abbia fornito queste due inutili transizioni!

Così:

Supponiamo che tu voglia eseguire una transizione ordinaria e comune come "slide". In tal caso, devi fare un'enorme quantità di lavoro! .

Quel lavoro, è spiegato in questo post.

Solo per ripetere:

Sorprendentemente: con iOS, se desideri le transizioni quotidiane più semplici, più comuni (come una normale diapositiva), devi eseguire tutto il lavoro di implementazione di una transizione completamente personalizzata .

Ecco come farlo ...

1. Hai bisogno di un'abitudine UIViewControllerAnimatedTransitioning

  1. Hai bisogno di un bool tuo popStyle. (Sta spuntando o saltando fuori?)

  2. Devi includere transitionDuration(banale) e la chiamata principale,animateTransition

  3. In effetti devi scrivere due diverse routine per dentro animateTransition. Uno per la spinta e uno per il pop. Probabilmente nominali animatePushe animatePop. All'interno animateTransition, basta diramare popStyleverso le due routine

  4. L'esempio seguente esegue un semplice spostamento / spostamento

  5. Nelle vostre animatePushe animatePoproutine. È necessario ottenere il "da visualizzare" e il "da visualizzare". (Come farlo, è mostrato nell'esempio di codice.)

  6. e devi addSubview per la nuova vista "to".

  7. e devi chiamare completeTransitionalla fine del tuo anime

Così ..

  class SimpleOver: NSObject, UIViewControllerAnimatedTransitioning {
        
        var popStyle: Bool = false
        
        func transitionDuration(
            using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.20
        }
        
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            
            if popStyle {
                
                animatePop(using: transitionContext)
                return
            }
            
            let fz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
            let tz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
            
            let f = transitionContext.finalFrame(for: tz)
            
            let fOff = f.offsetBy(dx: f.width, dy: 55)
            tz.view.frame = fOff
            
            transitionContext.containerView.insertSubview(tz.view, aboveSubview: fz.view)
            
            UIView.animate(
                withDuration: transitionDuration(using: transitionContext),
                animations: {
                    tz.view.frame = f
            }, completion: {_ in 
                    transitionContext.completeTransition(true)
            })
        }
        
        func animatePop(using transitionContext: UIViewControllerContextTransitioning) {
            
            let fz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
            let tz = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
            
            let f = transitionContext.initialFrame(for: fz)
            let fOffPop = f.offsetBy(dx: f.width, dy: 55)
            
            transitionContext.containerView.insertSubview(tz.view, belowSubview: fz.view)
            
            UIView.animate(
                withDuration: transitionDuration(using: transitionContext),
                animations: {
                    fz.view.frame = fOffPop
            }, completion: {_ in 
                    transitionContext.completeTransition(true)
            })
        }
    }

E poi ...

2. Usalo nel tuo controller di visualizzazione.

Nota: stranamente, devi farlo solo nel "primo" controller di visualizzazione. (Quello che è "sotto").

Con quello che fai apparire in cima , non fare nulla . Facile.

Quindi la tua classe ...

class SomeScreen: UIViewController {
}

diventa ...

class FrontScreen: UIViewController,
        UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {
    
    let simpleOver = SimpleOver()
    

    override func viewDidLoad() {
        
        super.viewDidLoad()
        navigationController?.delegate = self
    }

    func navigationController(
        _ navigationController: UINavigationController,
        animationControllerFor operation: UINavigationControllerOperation,
        from fromVC: UIViewController,
        to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        
        simpleOver.popStyle = (operation == .pop)
        return simpleOver
    }
}

Questo è tutto.

Push e pop esattamente come al solito, nessun cambiamento. Spingere ...

let n = UIStoryboard(name: "nextScreenStoryboardName", bundle: nil)
          .instantiateViewController(withIdentifier: "nextScreenStoryboardID")
          as! NextScreen
navigationController?.pushViewController(n, animated: true)

e per farlo apparire, puoi farlo nella schermata successiva:

class NextScreen: TotallyOrdinaryUIViewController {
    
    @IBAction func userClickedBackOrDismissOrSomethingLikeThat() {
        
        navigationController?.popViewController(animated: true)
    }
}

Uff.


3. Goditi anche le altre risposte in questa pagina che spiegano come sovrascrivere AnimatedTransitioning

Scorri fino a @AlanZeino e @elias answer per ulteriori discussioni su come fare AnimatedTransitioningnelle app iOS in questi giorni!


Eccellente! Se voglio che la navigazione scorri indietro, il gesto supporta anche lo stesso AnimatedTransitioning. Qualche idea?
Sam Chi Wen,

grazie @samchiwen - in effetti è esattamente cosa animatePushe animatePopsono .. le due diverse direzioni!
Fattie,

268

Ho fatto quanto segue e funziona benissimo .. ed è semplice e facile da capire ..

CATransition* transition = [CATransition animation];
transition.duration = 0.5;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
//transition.subtype = kCATransitionFromTop; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom
[self.navigationController.view.layer addAnimation:transition forKey:nil];
[[self navigationController] popViewControllerAnimated:NO];

E la stessa cosa per push ..


Versione Swift 3.0:

let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionFade
self.navigationController?.view.layer.add(transition, forKey: nil)
_ = self.navigationController?.popToRootViewController(animated: false)

34
+1, questa è davvero la soluzione più sana. Solo una piccola nota per i futuri visitatori: la Animated:NOparte è vitale. Se YESviene superato, le animazioni si mescolano e causano effetti divertenti.
DarkDust,

12
La migliore soluzione finora .. E per i principianti, non dimenticare di includere QuartCore (#import <QuartzCore / QuartzCore.h>)
nomann

4
L'unico problema che ho con questa soluzione è che il viewDontrApper del viewcontroller spinto viene chiamato immediatamente dopo che lo spingo senza animazione. C'è un modo per aggirarlo?
Pedro Mancheno,

9
Il mio problema con questo codice è che ogni vista sembra lampeggiare in grigio o bianco mentre scivolano dentro o fuori.
Chris,

1
controllato su iOS 7.1.2 e iOS 8.3 - questo codice funziona bene anche per il metodosetViewControllers:
proff

256

È così che sono sempre riuscito a completare questo compito.

Per Push:

MainView *nextView=[[MainView alloc] init];
[UIView  beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[self.navigationController pushViewController:nextView animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
[UIView commitAnimations];
[nextView release];

Per il pop:

[UIView  beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.navigationController.view cache:NO];
[UIView commitAnimations];

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelay:0.375];
[self.navigationController popViewControllerAnimated:NO];
[UIView commitAnimations];


Ricevo ancora molti feedback da questo, quindi vado avanti e lo aggiorno per utilizzare i blocchi di animazione che è il modo consigliato da Apple per fare comunque animazioni.

Per Push:

MainView *nextView = [[MainView alloc] init];
[UIView animateWithDuration:0.75
                         animations:^{
                             [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                             [self.navigationController pushViewController:nextView animated:NO];
                             [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
                         }];

Per il pop:

[UIView animateWithDuration:0.75
                         animations:^{
                             [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                             [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.navigationController.view cache:NO];
                         }];
[self.navigationController popViewControllerAnimated:NO];

3
Grazie per questo. Ma il pop viene eseguito automaticamente da UINavigationController. Come si sovrascrive quel comportamento in modo da poter chiamare la propria logica pop personalizzata?
Joshua Frank,

1
@stuckj in realtà funziona !!! devi solo sostituire superconself.navigationController
holierthanthou84

C'è un modo per ottenere una diapositiva da sinistra anziché la diapositiva predefinita da destra?
shim

Il primo non mostra affatto la nuova vista. Il secondo non mostra l'animazione. Risposta pessima! iOS 7.
Dmitry

2
perché hai dato la UIViewControllersottoclasse di un nome senza la parte "ViewController". Questo nome è più appropriato per UIView.
user2159978

29

per spinta

CATransition *transition = [CATransition animation];
transition.duration = 0.3;
transition.type = kCATransitionFade;
//transition.subtype = kCATransitionFromTop;

[self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
[self.navigationController pushViewController:ViewControllerYouWantToPush animated:NO];

per il pop

CATransition *transition = [CATransition animation];
transition.duration = 0.3;
transition.type = kCATransitionFade;
//transition.subtype = kCATransitionFromTop;

[self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
[self.navigationController popViewControllerAnimated:NO];

19

Risposta @Magnus, solo allora per Swift (2.0)

    let transition = CATransition()
    transition.duration = 0.5
    transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    transition.type = kCATransitionPush
    transition.subtype = kCATransitionFromTop
    self.navigationController!.view.layer.addAnimation(transition, forKey: nil)
    let writeView : WriteViewController = self.storyboard?.instantiateViewControllerWithIdentifier("WriteView") as! WriteViewController
    self.navigationController?.pushViewController(writeView, animated: false)

Alcuni sidenotes:

Puoi farlo anche con Segue, implementalo in prepareForSegueo shouldPerformSegueWithIdentifier. però , ciò manterrà anche l'animazione predefinita. Per risolvere questo problema, devi andare allo storyboard, fare clic sul Segue e deselezionare la casella "Animates". Ma questo limiterà la tua app per IOS 9.0 e versioni successive (almeno quando l'ho fatto in Xcode 7).

Quando si esegue in un seguito, le ultime due righe devono essere sostituite con:

self.navigationController?.popViewControllerAnimated(false)

Anche se ho impostato false, in qualche modo lo ignora.


Come rimuovere il colore nero in background alla fine dell'animazione.
Madhu,

Non funziona per l'animazione del controller vista push funziona per il controller vista pop
Mukul More

16

Ricorda che in Swift , l' estensione sono sicuramente i tuoi amici!

public extension UINavigationController {

    /**
     Pop current view controller to previous view controller.

     - parameter type:     transition animation type.
     - parameter duration: transition animation duration.
     */
    func pop(transitionType type: String = kCATransitionFade, duration: CFTimeInterval = 0.3) {
        self.addTransition(transitionType: type, duration: duration)
        self.popViewControllerAnimated(false)
    }

    /**
     Push a new view controller on the view controllers's stack.

     - parameter vc:       view controller to push.
     - parameter type:     transition animation type.
     - parameter duration: transition animation duration.
     */
    func push(viewController vc: UIViewController, transitionType type: String = kCATransitionFade, duration: CFTimeInterval = 0.3) {
        self.addTransition(transitionType: type, duration: duration)
        self.pushViewController(vc, animated: false)
    }

    private func addTransition(transitionType type: String = kCATransitionFade, duration: CFTimeInterval = 0.3) {
        let transition = CATransition()
        transition.duration = duration
        transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        transition.type = type
        self.view.layer.addAnimation(transition, forKey: nil)
    }

}

11

L'uso delle chiamate private è una cattiva idea poiché Apple non approva più le app che lo fanno. Forse potresti provare questo:

//Init Animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 0.50];


[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.navigationController.view cache:YES];

//Create ViewController
MyViewController *myVC = [[MyViewController alloc] initWith...];

[self.navigationController pushViewController:myVC animated:NO];
[myVC release];

//Start Animation
[UIView commitAnimations];

Funziona solo "a metà" - non risolverà il problema più difficile delle animazioni pop.
Adam,

Mi piace di più questa soluzione, e sì, funziona. L'uso di metodi privati ​​ti farà sicuramente rifiutare.
Benjamin Intal,

@nicktmro che è la chiamata API privata. Non me ne sono accorto.
Franklin,

@Franklin c'è stata una discussione qui qualche tempo fa sull'uso -pushViewController:transition:forceImmediate:che sarebbe stata una cattiva idea.
nicktmro,

9

Dato che questo è il miglior risultato su Google, ho pensato di condividere quello che penso sia il modo più sano; che consiste nell'utilizzare l'API di transizione iOS 7+. Ho implementato questo per iOS 10 con Swift 3.

È abbastanza semplice combinare questo con il modo in cui si UINavigationControlleranima tra due controller di visualizzazione se si crea una sottoclasse di UINavigationControllere si restituisce un'istanza di una classe conforme al UIViewControllerAnimatedTransitioningprotocollo.

Ad esempio, ecco la mia UINavigationControllersottoclasse:

class NavigationController: UINavigationController {
    init() {
        super.init(nibName: nil, bundle: nil)

        delegate = self
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension NavigationController: UINavigationControllerDelegate {

    public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return NavigationControllerAnimation(operation: operation)
    }

}

Puoi vedere che ho impostato il valore UINavigationControllerDelegatesu se stesso e in un'estensione nella mia sottoclasse implemento il metodo UINavigationControllerDelegateche ti consente di restituire un controller di animazione personalizzato (ovvero, NavigationControllerAnimation). Questo controller di animazione personalizzato sostituirà l'animazione stock per te.

Probabilmente ti starai chiedendo perché passo l'operazione NavigationControllerAnimationall'istanza tramite il suo inizializzatore. Lo faccio in modo tale che NavigationControllerAnimation, nell'implementazione del UIViewControllerAnimatedTransitioningprotocollo, sappia quale sia l'operazione (ovvero, "push" o "pop"). Questo aiuta a sapere che tipo di animazione dovrei fare. Il più delle volte, si desidera eseguire un'animazione diversa a seconda dell'operazione.

Il resto è piuttosto standard. Implementa le due funzioni richieste nel UIViewControllerAnimatedTransitioningprotocollo e anima come preferisci:

class NavigationControllerAnimation: NSObject, UIViewControllerAnimatedTransitioning {

    let operation: UINavigationControllerOperation

    init(operation: UINavigationControllerOperation) {
        self.operation = operation

        super.init()
    }

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

    public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
            let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) else { return }
        let containerView = transitionContext.containerView

        if operation == .push {
            // do your animation for push
        } else if operation == .pop {
            // do your animation for pop
        }
    }
}

È importante ricordare che per ogni diverso tipo di operazione (ad esempio, "push" o "pop"), i controller da e verso la vista saranno diversi. Quando si esegue un'operazione push, il controller per visualizzare sarà quello che viene premuto. Quando ci si trova in un'operazione pop, il controller di visualizzazione sarà quello a cui si sta eseguendo la transizione e il controller di visualizzazione sarà quello che viene visualizzato.

Inoltre, il tocontroller di visualizzazione deve essere aggiunto come sottoview containerViewnel contesto di transizione.

Al termine dell'animazione, è necessario chiamare transitionContext.completeTransition(true). Se stai eseguendo una transizione interattiva, dovrai restituire dinamicamente un Boola completeTransition(didComplete: Bool), a seconda che la transizione sia completa alla fine dell'animazione.

Infine ( lettura facoltativa ), potresti voler vedere come ho fatto la transizione su cui stavo lavorando. Questo codice è un po 'più confuso e l'ho scritto abbastanza rapidamente, quindi non direi che è un ottimo codice di animazione ma mostra comunque come eseguire la parte di animazione.

La mia è stata una transizione davvero semplice; Volevo imitare la stessa animazione di UINavigationController in genere, ma invece dell'animazione "Pagina successiva sopra", volevo implementare un'animazione 1: 1 del vecchio controller di vista contemporaneamente alla nuova vista appare il controller. Ciò ha l'effetto di far sembrare i due controller di vista come se fossero bloccati l'uno all'altro.

Per l'operazione push, ciò richiede prima di impostare l' toViewControllerorigine della vista sullo schermo dell'asse x, aggiungendola come sottoview della containerView, animandola sullo schermo impostandola origin.xsu zero. Allo stesso tempo, anima la fromViewControllervista di distanza impostandola origin.xfuori dallo schermo:

toViewController.view.frame = containerView.bounds.offsetBy(dx: containerView.frame.size.width, dy: 0.0)

containerView.addSubview(toViewController.view)

UIView.animate(withDuration: transitionDuration(using: transitionContext),
               delay: 0,
               options: [ UIViewAnimationOptions.curveEaseOut ],
               animations: {
                toViewController.view.frame = containerView.bounds
                fromViewController.view.frame = containerView.bounds.offsetBy(dx: -containerView.frame.size.width, dy: 0)
},
               completion: { (finished) in
                transitionContext.completeTransition(true)
})

L'operazione pop è sostanzialmente l'inverso. Aggiungi toViewControllercome sottoview di containerView, e anima via fromViewControllera destra mentre anima in toViewControllerda sinistra:

containerView.addSubview(toViewController.view)

UIView.animate(withDuration: transitionDuration(using: transitionContext),
               delay: 0,
               options: [ UIViewAnimationOptions.curveEaseOut ],
               animations: {
                fromViewController.view.frame = containerView.bounds.offsetBy(dx: containerView.frame.width, dy: 0)
                toViewController.view.frame = containerView.bounds
},
               completion: { (finished) in
                transitionContext.completeTransition(true)
})

Ecco un riassunto con l'intero file rapido:

https://gist.github.com/alanzeino/603293f9da5cd0b7f6b60dc20bc766be


Grande!. Quello che volevo fare è SOLO animare in direzione opposta. Ho esaminato alcune altre soluzioni, ma tutte mostrano un lampeggiamento sullo schermo sinistro e destro. Sembra che l'animazione implicita del cambio alfa non possa essere rimossa con loro. Solo questa soluzione ha risolto il problema.
beshio,

sì, questa è l'unica soluzione moderna corretta. (Non mi dispiace, ma è esattamente la stessa della soluzione che ho scritto di seguito! :))
Fattie

@AlanZeino Cosa succede se all'interno dello stesso ViewController è necessario disporre di animazioni diverse per fare clic su un pulsante diverso? Quindi, per button1 è necessaria un'animazione dissolvente, per button2 è necessaria la transizione predefinita.
jzeferino,

7

Ci sono UINavigationControllerDelegate e UIViewControllerAnimatedTransitioning lì puoi cambiare l'animazione per tutto quello che vuoi.

Ad esempio questa è l'animazione pop verticale per VC:

@objc class PopAnimator: NSObject, UIViewControllerAnimatedTransitioning {

func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
    return 0.5
}

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let containerView = transitionContext.containerView()
    let bounds = UIScreen.mainScreen().bounds
    containerView!.insertSubview(toViewController.view, belowSubview: fromViewController.view)
    toViewController.view.alpha = 0.5

    let finalFrameForVC = fromViewController.view.frame

    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
        fromViewController.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.height)
        toViewController.view.alpha = 1.0
        }, completion: {
            finished in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
    })
}

}

E poi

func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    if operation == .Pop {
        return PopAnimator()
    }
    return nil;
}

Tutorial utile https://www.objc.io/issues/5-ios7/view-controller-transitions/


6

Basato sulla risposta aggiornata per swift 4jordanperry

Per la spinta UIViewController

let yourVC = self.storyboard?.instantiateViewController(withIdentifier: "yourViewController") as! yourViewController
    UIView.animate(withDuration: 0.75, animations: {() -> Void in
    UIView.setAnimationCurve(.easeInOut)
    self.navigationController?.pushViewController(terms, animated: true)
    UIView.setAnimationTransition(.flipFromRight, for: (self.navigationController?.view)!, cache: false)
})

Per il pop

UIView.animate(withDuration: 0.75, animations: {() -> Void in
    UIView.setAnimationCurve(.easeInOut)
    UIView.setAnimationTransition(.flipFromLeft, for: (self.navigationController?.view)!, cache: false)
})
navigationController?.popViewController(animated: false)

5

Ecco come ho fatto lo stesso in Swift:

Per Push:

    UIView.animateWithDuration(0.75, animations: { () -> Void in
        UIView.setAnimationCurve(UIViewAnimationCurve.EaseInOut)
        self.navigationController!.pushViewController(nextView, animated: false)
        UIView.setAnimationTransition(UIViewAnimationTransition.FlipFromRight, forView: self.navigationController!.view!, cache: false)
    })

Per il pop:

In realtà l'ho fatto in modo leggermente diverso rispetto ad alcune delle risposte precedenti, ma poiché sono nuovo nello sviluppo di Swift, potrebbe non essere giusto. Ho ignorato viewWillDisappear:animated:e aggiunto il codice pop lì dentro:

    UIView.animateWithDuration(0.75, animations: { () -> Void in
        UIView.setAnimationCurve(UIViewAnimationCurve.EaseInOut)
        UIView.setAnimationTransition(UIViewAnimationTransition.FlipFromLeft, forView: self.navigationController!.view, cache: false)
    })

    super.viewWillDisappear(animated)

5

@Luca Davanzo's answer in Swift 4.2

public extension UINavigationController {

    /**
     Pop current view controller to previous view controller.

     - parameter type:     transition animation type.
     - parameter duration: transition animation duration.
     */
    func pop(transitionType type: CATransitionType = .fade, duration: CFTimeInterval = 0.3) {
        self.addTransition(transitionType: type, duration: duration)
        self.popViewController(animated: false)
    }

    /**
     Push a new view controller on the view controllers's stack.

     - parameter vc:       view controller to push.
     - parameter type:     transition animation type.
     - parameter duration: transition animation duration.
     */
    func push(viewController vc: UIViewController, transitionType type: CATransitionType = .fade, duration: CFTimeInterval = 0.3) {
        self.addTransition(transitionType: type, duration: duration)
        self.pushViewController(vc, animated: false)
    }

    private func addTransition(transitionType type: CATransitionType = .fade, duration: CFTimeInterval = 0.3) {
        let transition = CATransition()
        transition.duration = duration
        transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
        transition.type = type
        self.view.layer.add(transition, forKey: nil)
    }

}

4

Di recente stavo cercando di fare qualcosa di simile. Ho deciso che non mi piaceva l'animazione scorrevole di UINavigationController, ma non volevo nemmeno fare le animazioni che UIView ti dà come un ricciolo o qualcosa del genere. Volevo fare una dissolvenza incrociata tra le viste quando spingo o suono.

Il problema in questo caso consiste nel fatto che la vista sta letteralmente rimuovendo la vista o facendone apparire una sopra quella corrente, quindi una dissolvenza non funziona. La soluzione a cui sono arrivato consisteva nel prendere la mia nuova vista e aggiungerla come sottoview alla vista superiore corrente nello stack di UIViewController. Lo aggiungo con un alfa di 0, quindi eseguo una dissolvenza incrociata. Al termine della sequenza di animazione, inserisco la vista nello stack senza animarla. Quindi torno al vecchio topView e pulisco le cose che avevo cambiato.

È un po 'più complicato di così, perché hai gli elementi di navigazione che devi regolare per rendere la transizione corretta. Inoltre, se si esegue una rotazione, è necessario regolare le dimensioni dei fotogrammi quando si aggiungono le visualizzazioni come visualizzazioni secondarie in modo che vengano visualizzate correttamente sullo schermo. Ecco un po 'del codice che ho usato. Ho eseguito la sottoclasse di UINavigationController e ho annullato i metodi push e pop.

-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
      UIViewController *currentViewController = [self.viewControllers lastObject];
      //if we don't have a current controller, we just do a normal push
      if(currentViewController == nil)
      {
         [super pushViewController:viewController animated:animated];
         return;
      }
      //if no animation was requested, we can skip the cross fade
      if(!animation)
      {
         [super pushViewController:viewController animated:NO];
         return;
      }
      //start the cross fade.  This is a tricky thing.  We basically add the new view
//as a subview of the current view, and do a cross fade through alpha values.
//then we push the new view on the stack without animating it, so it seemlessly is there.
//Finally we remove the new view that was added as a subview to the current view.

viewController.view.alpha = 0.0;
//we need to hold onto this value, we'll be releasing it later
    NSString *title = [currentViewController.title retain];

//add the view as a subview of the current view
[currentViewController.view addSubview:viewController.view];
[currentViewController.view bringSubviewToFront:viewController.view];
UIBarButtonItem *rButtonItem = currentViewController.navigationItem.rightBarButtonItem;
UIBarButtonItem *lButtonItem = currentViewController.navigationItem.leftBarButtonItem;

NSArray *array = nil;

//if we have a right bar button, we need to add it to the array, if not, we will crash when we try and assign it
//so leave it out of the array we are creating to pass as the context.  I always have a left bar button, so I'm not checking to see if it is nil. Its a little sloppy, but you may want to be checking for the left BarButtonItem as well.
if(rButtonItem != nil)
    array = [[NSArray alloc] initWithObjects:currentViewController,viewController,title,lButtonItem,rButtonItem,nil];
else {
    array = [[NSArray alloc] initWithObjects:currentViewController,viewController,title,lButtonItem,nil];
}

//remove the right bar button for our transition
[currentViewController.navigationItem setRightBarButtonItem:nil animated:YES];
//remove the left bar button and create a backbarbutton looking item
//[currentViewController.navigationItem setLeftBarButtonItem:nil animated:NO];

//set the back button
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:title style:kButtonStyle target:self action:@selector(goBack)];
[currentViewController.navigationItem setLeftBarButtonItem:backButton animated:YES];
[viewController.navigationItem setLeftBarButtonItem:backButton animated:NO];
[backButton release];

[currentViewController setTitle:viewController.title];

[UIView beginAnimations:@"push view" context:array];
[UIView setAnimationDidStopSelector:@selector(animationForCrossFadePushDidStop:finished:context:)];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.80];
[viewController.view setAlpha: 1.0];
[UIView commitAnimations];
}

-(void)animationForCrossFadePushDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{

UIViewController *c = [(NSArray*)context objectAtIndex:0];
UIViewController *n = [(NSArray*)context objectAtIndex:1];
NSString *title     = [(NSArray *)context objectAtIndex:2];
UIBarButtonItem *l = [(NSArray *)context objectAtIndex:3];
UIBarButtonItem *r = nil;
//not all views have a right bar button, if we look for it and it isn't in the context,
//we'll crash out and not complete the method, but the program won't crash.
//So, we need to check if it is there and skip it if it isn't.
if([(NSArray *)context count] == 5)
    r = [(NSArray *)context objectAtIndex:4];

//Take the new view away from being a subview of the current view so when we go back to it
//it won't be there anymore.
[[[c.view subviews] lastObject] removeFromSuperview];
[c setTitle:title];
[title release];
//set the search button
[c.navigationItem setLeftBarButtonItem:l animated:NO];
//set the next button
if(r != nil)
    [c.navigationItem setRightBarButtonItem:r animated:NO];


[super pushViewController:n animated:NO];

 }

Come accennato nel codice, ho sempre un elemento del pulsante della barra a sinistra, quindi non controllo per vedere se è nullo prima di inserirlo nell'array che passo come contesto per il delegato dell'animazione. Se lo fai, potresti voler fare quel controllo.

Il problema che ho riscontrato è che se si arresta in modo anomalo nel metodo delegato, il programma non si arresterà in modo anomalo. Impedisce il completamento del delegato ma non viene visualizzato alcun tipo di avviso.
Quindi, poiché stavo facendo la mia pulizia in quella routine delegata, stava causando uno strano comportamento visivo poiché non stava finendo la pulizia.

Il pulsante Indietro che creo chiama un metodo "goBack" e quel metodo chiama semplicemente la routine pop.

-(void)goBack
{ 
     [self popViewControllerAnimated:YES];
}

Inoltre, ecco la mia routine pop.

-(UIViewController *)popViewControllerAnimated:(BOOL)animated
{
    //get the count for the number of viewControllers on the stack
int viewCount = [[self viewControllers] count];
//get the top view controller on the stack
UIViewController *topViewController = [self.viewControllers objectAtIndex:viewCount - 1];
//get the next viewController after the top one (this will be the new top one)
UIViewController *newTopViewController = [self.viewControllers objectAtIndex:viewCount - 2];

//if no animation was requested, we can skip the cross fade
if(!animated)
{
    [super popViewControllerAnimated:NO];
            return topViewController;
}



//start of the cross fade pop.  A bit tricky.  We need to add the new top controller
//as a subview of the curent view controler with an alpha of 0.  We then do a cross fade.
//After that we pop the view controller off the stack without animating it.
//Then the cleanup happens: if the view that was popped is not released, then we
//need to remove the subview we added and change some titles back.
newTopViewController.view.alpha = 0.0;
[topViewController.view addSubview:newTopViewController.view];
[topViewController.view bringSubviewToFront:newTopViewController.view];
NSString *title = [topViewController.title retain];
UIBarButtonItem *lButtonItem = topViewController.navigationItem.leftBarButtonItem;
UIBarButtonItem *rButtonItem = topViewController.navigationItem.rightBarButtonItem;

//set the new buttons on top of the current controller from the new top controller
if(newTopViewController.navigationItem.leftBarButtonItem != nil)
{
    [topViewController.navigationItem setLeftBarButtonItem:newTopViewController.navigationItem.leftBarButtonItem animated:YES];
}
if(newTopViewController.navigationItem.rightBarButtonItem != nil)
{
    [topViewController.navigationItem setRightBarButtonItem:newTopViewController.navigationItem.rightBarButtonItem animated:YES];
}

[topViewController setTitle:newTopViewController.title];
//[topViewController.navigationItem.leftBarButtonItem setTitle:newTopViewController.navigationItem.leftBarButtonItem.title];

NSArray *array = nil;
if(rButtonItem != nil)
    array = [[NSArray alloc] initWithObjects:topViewController,title,lButtonItem,rButtonItem,nil];
else {
    array = [[NSArray alloc] initWithObjects:topViewController,title,lButtonItem,nil];
}


[UIView beginAnimations:@"pop view" context:array];
[UIView setAnimationDidStopSelector:@selector(animationForCrossFadePopDidStop:finished:context:)];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.80];
[newTopViewController.view setAlpha: 1.0];
[UIView commitAnimations];
return topViewController;

 }

 -(void)animationForCrossFadePopDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
 {

UIViewController *c = [(NSArray *)context objectAtIndex:0];
//UIViewController *n = [(NSArray *)context objectAtIndex:1];
NSString *title = [(NSArray *)context objectAtIndex:1];
UIBarButtonItem *l = [(NSArray *)context objectAtIndex:2];
UIBarButtonItem *r = nil;



//Not all views have a right bar button.  If we look for one that isn't there
// we'll crash out and not complete this method, but the program will continue.
//So we need to check if it is therea nd skip it if it isn't.
if([(NSArray *)context count] == 4)
    r = [(NSArray *)context objectAtIndex:3];

//pop the current view from the stack without animation
[super popViewControllerAnimated:NO];

//if what was the current veiw controller is not nil, then lets correct the changes
//we made to it.
if(c != nil)
{
    //remove the subview we added for the transition
    [[c.view.subviews lastObject] removeFromSuperview];
    //reset the title we changed
    c.title = title;
    [title release];
    //replace the left bar button that we changed
    [c.navigationItem setLeftBarButtonItem:l animated:NO];
    //if we were passed a right bar button item, replace that one as well
    if(r != nil)
        [c.navigationItem setRightBarButtonItem:r animated:NO];
    else {
        [c.navigationItem setRightBarButtonItem:nil animated:NO];
    }


 }
}

È praticamente tutto. Avrai bisogno di un codice aggiuntivo se desideri implementare le rotazioni. Dovrai impostare la dimensione del fotogramma delle viste che aggiungi come viste secondarie prima di mostrarle, altrimenti ti imbatterai in problemi l'orientamento è orizzontale, ma l'ultima volta che hai visto la vista precedente era verticale. Quindi, lo aggiungi come una vista secondaria e lo dissolvi in ​​ma appare come ritratto, quindi quando pop senza animazione, la stessa vista, ma quella che è nella pila, ora è orizzontale. Il tutto sembra un po 'funky. L'implementazione della rotazione di tutti è un po 'diversa, quindi non ho incluso il mio codice qui.

Spero che aiuti alcune persone. Ho cercato qualcosa del genere e non sono riuscito a trovare nulla. Non penso che questa sia la risposta perfetta, ma a questo punto funziona davvero bene per me.


Anche se ammirevole, questa non è onestamente la soluzione ora 7 anni dopo!
Fattie

Hai ragione. Questa risposta era del 2011. Funzionava allora, ma da allora le cose sono cambiate molto. =)
georryan

4

Ora puoi usare UIView.transition. Si noti che animated:false. Funziona con qualsiasi opzione di transizione, pop, push o sostituzione dello stack.

if let nav = self.navigationController
{
    UIView.transition(with:nav.view, duration:0.3, options:.transitionCrossDissolve, animations: {
        _ = nav.popViewController(animated:false)
    }, completion:nil)
}

1
@Fattie, questo particolare metodo funziona solo con una qualsiasi delle animazioni standard come lanci e riccioli elencati in developer.apple.com/documentation/uikit/uiviewanimationoptions
Peter DeWeese,

3

Usando la risposta di iJordan come ispirazione, perché non creare semplicemente una Categoria su UINavigationController da usare in tutta la tua app invece di copiare / incollare questo codice di animazione ovunque?

UINavigationController + Animation.h

@interface UINavigationController (Animation)

- (void) pushViewControllerWithFlip:(UIViewController*) controller;

- (void) popViewControllerWithFlip;

@end

UINavigationController + Animation.m

@implementation UINavigationController (Animation)

- (void) pushViewControllerWithFlip:(UIViewController *) controller
{
    [UIView animateWithDuration:0.50
                     animations:^{
                         [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                         [self pushViewController:controller animated:NO];
                         [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];
                     }];
}

- (void) popViewControllerWithFlip
{
    [UIView animateWithDuration:0.5
                     animations:^{
                         [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                         [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];
                     }];

    [self popViewControllerAnimated:NO];
}

@end

Quindi importa semplicemente il file UINavigationController + Animation.h e chiamalo normalmente:

[self.navigationController pushViewControllerWithFlip:[[NewViewController alloc] init]];

[self.navigationController popViewControllerWithFlip];

Intelligente. Ma perché non aggiungere metodi push / pop che accettano un argomento di UIViewAnimationTransition piuttosto che hardcode su flipFromRight?
Jef

@Jef questi sono metodi convenienti: in questo modo, l'implementatore non ha bisogno di ricordare quale valore UIViewAnimationTransition trasmettere per ogni tipo di animazione specifica, chiamano semplicemente il metodo con il nome "inglese" di ciò che vogliono realizzare.
DiscDev

@Jef anche, il tuo suggerimento è sicuramente valido - se stavo ancora usando object-c e avessi bisogno di supportare molti stili di transizione (sicuramente sconsigliato poiché molti stili di transizione diversi confonderanno gli utenti) Avrei 1 metodo che prende il tipo UIViewAnimationTransition, quindi diversi metodi di praticità per facilitare lo sviluppo.
DiscDev

3

È molto semplice

self.navigationController?.view.semanticContentAttribute = .forceRightToLeft

Benvenuto in StackOverflow: se pubblichi esempi di codice, XML o dati, evidenzia quelle righe nell'editor di testo e fai clic sul pulsante "Esempi di codice" ({}) sulla barra degli strumenti dell'editor o usando Ctrl + K sulla tastiera per formattare in modo corretto e la sintassi lo evidenzia!
WhatsThePoint,

2

Dai un'occhiata a ADTransitionController , un calo in sostituzione di UINavigationController con animazioni di transizione personalizzate (la sua API corrisponde all'API di UINavigationController) che abbiamo creato in Applidium.

È possibile utilizzare diverse animazioni predefinite per azioni push e pop come Swipe , Fade , Cube , Carrousel , Zoom e così via.


2

Mentre tutte le risposte qui sono fantastiche e la maggior parte funziona molto bene, esiste un metodo leggermente più semplice che ottiene lo stesso effetto ...

Per Push:

  NextViewController *nextViewController = [[NextViewController alloc] init];

  // Shift the view to take the status bar into account 
  CGRect frame = nextViewController.view.frame;
  frame.origin.y -= 20;
  frame.size.height += 20;
  nextViewController.view.frame = frame;

  [UIView transitionFromView:self.navigationController.topViewController.view toView:nextViewController.view duration:0.5 options:UIViewAnimationOptionTransitionFlipFromRight completion:^(BOOL finished) {
    [self.navigationController pushViewController:nextViewController animated:NO];
  }];

Per il pop:

  int numViewControllers = self.navigationController.viewControllers.count;
  UIView *nextView = [[self.navigationController.viewControllers objectAtIndex:numViewControllers - 2] view];

  [UIView transitionFromView:self.navigationController.topViewController.view toView:nextView duration:0.5 options:UIViewAnimationOptionTransitionFlipFromLeft completion:^(BOOL finished) {
    [self.navigationController popViewControllerAnimated:NO];
  }];}

Questo si arresterà in modo anomalo quando si aprirà il controller della vista principale.
Abdullah Umer,

1

Non sono a conoscenza di alcun modo per modificare pubblicamente l'animazione di transizione.

Se il pulsante "indietro" non è necessario, è necessario utilizzare i controller di visualizzazione modale per avere le transizioni "push from bottom" / "flip" / "fade" / (≥3.2) "page curl".


Sul lato privato , il metodo -pushViewController:animated:chiama il metodo non documentato -pushViewController:transition:forceImmediate:, quindi, ad esempio, se si desidera una transizione capovolgere da sinistra a destra, è possibile utilizzare

[navCtrler pushViewController:ctrler transition:10 forceImmediate:NO];

Tuttavia, non è possibile modificare la transizione "pop" in questo modo.


1

Vedi la mia risposta a questa domanda per un modo di farlo in molte meno righe di codice. Questo metodo consente di animare una pseudo- "Push" di un nuovo controller di visualizzazione nel modo desiderato e, al termine dell'animazione, imposta il controller di navigazione come se si fosse utilizzato il metodo Push standard. Il mio esempio ti permette di animare uno slide-in da sinistra o da destra. Codice ripetuto qui per comodità:

-(void) showVC:(UIViewController *) nextVC rightToLeft:(BOOL) rightToLeft {
    [self addChildViewController:neighbor];
    CGRect offscreenFrame = self.view.frame;
    if(rightToLeft) {
        offscreenFrame.origin.x = offscreenFrame.size.width * -1.0;
    } else if(direction == MyClimbDirectionRight) {
        offscreenFrame.origin.x = offscreenFrame.size.width;
    }
    [[neighbor view] setFrame:offscreenFrame];
    [self.view addSubview:[neighbor view]];
    [neighbor didMoveToParentViewController:self];
    [UIView animateWithDuration:0.5 animations:^{
        [[neighbor view] setFrame:self.view.frame];
    } completion:^(BOOL finished){
        [neighbor willMoveToParentViewController:nil];
        [neighbor.view removeFromSuperview];
        [neighbor removeFromParentViewController];
        [[self navigationController] pushViewController:neighbor animated:NO];
        NSMutableArray *newStack = [[[self navigationController] viewControllers] mutableCopy];
        [newStack removeObjectAtIndex:1]; //self, just below top
        [[self navigationController] setViewControllers:newStack];
    }];
}

0

Dall'app di esempio, controlla questa variante. https://github.com/mpospese/MPFoldTransition/

#pragma mark - UINavigationController(MPFoldTransition)

@implementation UINavigationController(MPFoldTransition)

//- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
- (void)pushViewController:(UIViewController *)viewController foldStyle:(MPFoldStyle)style
{
    [MPFoldTransition transitionFromViewController:[self visibleViewController] 
                                  toViewController:viewController 
                                          duration:[MPFoldTransition defaultDuration]  
                                             style:style 
                                        completion:^(BOOL finished) {
                                            [self pushViewController:viewController animated:NO];
                                        }
     ];
}

- (UIViewController *)popViewControllerWithFoldStyle:(MPFoldStyle)style
{
    UIViewController *toController = [[self viewControllers] objectAtIndex:[[self viewControllers] count] - 2];

    [MPFoldTransition transitionFromViewController:[self visibleViewController] 
                                  toViewController:toController 
                                          duration:[MPFoldTransition defaultDuration] 
                                             style:style
                                        completion:^(BOOL finished) {
                                            [self popViewControllerAnimated:NO];
                                        }
     ];

    return toController;
}

0

Usa solo:

ViewController *viewController = [[ViewController alloc] init];

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
navController.navigationBarHidden = YES;

[self presentViewController:navController animated:YES completion: nil];
[viewController release];
[navController release];

0

Realizzare questa è una vecchia domanda. Vorrei ancora pubblicare questa risposta, in quanto ho riscontrato alcuni problemi viewControllerscon alcune delle risposte proposte. La mia soluzione è la sottoclasseUINavigationController e sovrascrivere tutti i metodi pop e push.

FlippingNavigationController.h

@interface FlippingNavigationController : UINavigationController

@end

FlippingNavigationController.m:

#import "FlippingNavigationController.h"

#define FLIP_DURATION 0.5

@implementation FlippingNavigationController

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    [UIView transitionWithView:self.view
                      duration:animated?FLIP_DURATION:0
                       options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionTransitionFlipFromRight
                    animations:^{ [super pushViewController:viewController
                                                   animated:NO]; }
                    completion:nil];
}

- (UIViewController *)popViewControllerAnimated:(BOOL)animated
{
    return [[self popToViewController:[self.viewControllers[self.viewControllers.count - 2]]
                             animated:animated] lastObject];
}

- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated
{
    return [self popToViewController:[self.viewControllers firstObject]
                            animated:animated];
}

- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    __block NSArray* viewControllers = nil;

    [UIView transitionWithView:self.view
                      duration:animated?FLIP_DURATION:0
                       options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionTransitionFlipFromLeft
                    animations:^{ viewControllers = [super popToViewController:viewController animated:NO]; }
                    completion:nil];

    return viewControllers;
}

@end

0

So che questa discussione è vecchia, ma ho pensato di aggiungere due centesimi. Non è necessario creare un'animazione personalizzata, esiste un modo semplice (forse confuso) di farlo. Invece di utilizzare push, creare un nuovo controller di navigazione, rendere il nuovo controller di visualizzazione il controller di visualizzazione radice di quel controller di navigazione e quindi presentare il controller di navigazione dal controller di navigazione originale. Presente è facilmente personalizzabile con molti stili e non è necessario creare un'animazione personalizzata.

Per esempio:

UIViewcontroller viewControllerYouWantToPush = UIViewController()
UINavigationController newNavController = UINavigationController(root: viewControllerYouWantToView)
newNavController.navBarHidden = YES;
self.navigationController.present(newNavController)

E puoi cambiare lo stile di presentazione come preferisci.


-1

Ho trovato un modo leggermente ricorsivo per farlo che funziona per i miei scopi. Ho una variabile BOOL di istanza che uso per bloccare la normale animazione pop-up e sostituire il mio messaggio pop non animato. La variabile è inizialmente impostata su NO. Quando si tocca il pulsante Indietro, il metodo delegato lo imposta su SÌ e invia un nuovo messaggio pop non animato alla barra di navigazione, richiamando quindi lo stesso metodo delegato, questa volta con la variabile impostata su SÌ. Con la variabile impostata su SÌ, il metodo delegato la imposta su NO e restituisce SÌ per consentire il pop non animato. Dopo la seconda chiamata del delegato, torniamo alla prima, dove NO viene restituito, bloccando il pop animato originale! In realtà non è così disordinato come sembra. Il mio metodo shouldPopItem è simile al seguente:

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item 
{
    if ([[navigationBar items] indexOfObject:item] == 1) 
    {
        [expandedStack restack];    
    }

    if (!progPop) 
    {
        progPop = YES;
        [navBar popNavigationItemAnimated:NO];
        return NO;
    }
    else 
    {
        progPop = NO;
        return YES;
    }
}

Per me va bene.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.