Navigasyon tabanlı bir uygulamada Push ve Pop animasyonları nasıl değiştirilir?


221

Navigasyon tabanlı bir uygulamam var ve push ve pop animasyonlarının animasyonunu değiştirmek istiyorum. Bunu nasıl yaparım?

2018'i düzenle

Bu soruya birçok cevap geldi ve şimdi oldukça uzun süredir, şimdi en alakalı olduğuna inandığım şeyin cevabını tekrar seçtim. Başka türlü düşünen biri varsa lütfen yorumlarda bana bildirin


25
İOS 7'den itibaren bunun için resmi API var; bkz. UINavigationControllerDelegate'in özel geçiş animasyonu desteği. Bununla ilgili bir WWDC 2013 videosu da var.
Jesse Rusak

Swift'te bunu yapmak için bir cevap ekledim - bu soruya Swift uygulamaları hakkında soru sordum, bu yüzden sonraki uygulamamla karşılaşacağımı düşündüm.
djbp

1
Resmi (iOS 7+) API ile çok iyi bir öğretici için bkz. Bradbambara.wordpress.com/2014/04/11/…
nikolovski

1
@JesseRusak WWDC 2013 bağlantısını güncelledi Video: developer.apple.com/videos/play/wwdc2013-218
Wojciech Rutkowski

1
Kabul edilen cevap arkadaşım değişti. Bu yardımcı olur umarım! GLHF
Jab

Yanıtlar:


35

Navigasyon tabanlı bir uygulamada Push ve Pop animasyonları nasıl değiştirilir ...

2019 için "son cevap!"

Önsöz:

İOS geliştirmede yeni olduğunuzu varsayalım. Kafa karıştırıcı bir şekilde, Apple kolayca kullanılabilecek iki geçiş sağlar. Bunlar: "crossfade" ve "flip".

Ama elbette, "crossfade" ve "flip" işe yaramaz. Asla kullanılmazlar. Kimse Apple'ın neden bu iki işe yaramaz geçişi sağladığını bilmiyor!

Yani:

"Slayt" gibi sıradan, ortak bir geçiş yapmak istediğinizi varsayalım. Bu durumda, BÜYÜK miktarda iş yapmak zorundasınız!.

Bu çalışma, bu yazıda açıklanmıştır.

Sadece tekrarlamak için:

Şaşırtıcı bir şekilde: iOS ile, en basit, en yaygın, günlük geçişleri (sıradan bir slayt gibi) istiyorsanız, tam bir özel geçiş uygulamak için tüm çalışmalara sahip olmanız gerekir. .

İşte nasıl yapılacağı ...

1. bir özel gerekir UIViewControllerAnimatedTransitioning

  1. Kendinize ait bir boole ihtiyacınız var popStyle. (Patlıyor mu yoksa patlıyor mu?)

  2. transitionDuration(Önemsiz) ve ana aramayı dahil etmelisiniz ,animateTransition

  3. Aslında sen gerekir içeriden için iki farklı rutinleri yazma animateTransition. Biri itme, diğeri de pop. Muhtemelen onları adlandırın animatePushve animatePop. İçeride animateTransition, popStyleiki rutine dalın

  4. Aşağıdaki örnek basit bir hareket / hareket

  5. Sizin animatePushve animatePoprutinlerinizde. Sen gerekir "manzarayı" ve "görünümüne" olsun. (Bunun nasıl yapılacağı, kod örneğinde gösterilir.)

  6. ve yeni "görüntüleme" görünümü için gerekir addSubview .

  7. ve gereken çağrı completeTransitioniçin anime sonunda

Yani ..

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

Ve sonra ...

2. Görünüm denetleyicinizde kullanın.

Not: garip bir şekilde, sadece bunu yapmak zorundasın "ilk" görünüm denetleyicisinde . ("Altta olan".)

En üste attığınla hiçbir şey yapma . Kolay.

Yani sınıfınız ...

class SomeScreen: UIViewController {
}

olur ...

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

Bu kadar.

Tam olarak normal şekilde itin ve pop, değişiklik yok. İtmek ...

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

ve pop yapmak için, bunu bir sonraki ekranda yapmak isterseniz:

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

Uf.


3. Bu sayfadaki AnimatedTransitioning'in nasıl geçersiz kılınacağını açıklayan diğer cevapların da tadını çıkarın

Bugünlerde AnimatedTransitioningiOS uygulamalarında nasıl yapılacağı hakkında daha fazla tartışma için @AlanZeino ve @elias yanıtına gidin !


Mükemmel! Ben gezinme tokatlamak geri jest de aynı AnimatedTransitioning desteklemek istiyorsanız. Herhangi bir fikir?
sam chi wen

teşekkürler @samchiwen - gerçekten tam olarak ne olduğunu animatePushve animatePop.. iki farklı yön!
Fattie

268

Aşağıdakileri yaptım ve iyi çalışıyor .. ve basit ve anlaşılması kolay ..

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];

Ve aynı şey itmek için ..


Swift 3.0 sürümü:

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, bu gerçekten en akılcı çözüm. Gelecekteki ziyaretçiler için küçük bir not: Animated:NOkısım hayati önem taşıyor. Eğer YESgeçirilir, animasyonlar karıştırın ve komik etkilere neden.
DarkDust

12
Şimdiye kadarki en iyi çözüm .. Ve yeni başlayanlar için QuartCore (#import <QuartzCore / QuartzCore.h>)
nomann

4
Ben itti viewcontroller'ın viewDidAppear animasyon olmadan ittikten hemen sonra bu çözüm ile sahip tek sorun var. etrafında yol var mı?
Pedro Mancheno

9
Bu kodla ilgili sorunum, her görünümün içeri veya dışarı kaydırıldıklarında gri veya beyaz renkte yanıp sönmesi gibi görünüyor.
Chris

1
Bu kod yöntemi cezasını çalışma da iyi çalışıyor - iOS 7.1.2 ve iOS 8.3 işaretlisetViewControllers:
proff

256

Ben her zaman bu görevi tamamlamayı başardım.

İtme için:

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];

Pop için:

[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];


Bundan hala çok fazla geri bildirim alıyorum, bu yüzden Apple'a animasyonlar yapmanın önerilen yolu olan animasyon bloklarını kullanacak şekilde güncelleyeceğim.

İtme için:

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

Pop için:

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

3
Bunun için teşekkürler. Ancak pop UINavigationController tarafından otomatik olarak yapılır. Özel pop mantığınızı çağırabilmeniz için bu davranışı nasıl geçersiz kılabilirsiniz?
Joshua Frank

1
@ stuckj aslında işe yarıyor !!! Sadece değiştirmek zorunda supertarafındanself.navigationController
holierthanthou84

Sağdan varsayılan slayt yerine soldan slayt almanın herhangi bir yolu var mı?
shim

Birincisi yeni görünümü hiç göstermiyor. İkincisi animasyon göstermiyor. Çok kötü cevap! iOS 7.
Dmitry

2
neden UIViewController"ViewController" bölümü olmadan bir adı alt sınıfa verdiniz . Bu ad UIView için daha uygundur.
user2159978

29

itmek için

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];

pop için

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

@Magnus yanıtı, ancak Swift için (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)

Bazı sidenotlar:

Bunu Segue ile de yapabilirsiniz, sadece prepareForSegueveya içine uygulayın shouldPerformSegueWithIdentifier. ancak , bu varsayılan animasyonu da içinde tutacaktır. Bunu düzeltmek için film şeridine gitmeniz, Segue'i tıklamanız ve 'Animates' kutusunun işaretini kaldırmanız gerekir. Ancak bu, IOS 9.0 ve üstü için uygulamanızı sınırlar (en azından Xcode 7'de yaptığım zaman).

Bir segue yaparken, son iki satır aşağıdaki ile değiştirilmelidir:

self.navigationController?.popViewControllerAnimated(false)

Yanlış ayarlamış olmama rağmen, bunu görmezden geliyor.


Animasyonun sonunda arka planda siyah renk nasıl kaldırılır.
Madhu

Push view denetleyici animasyonu için çalışmıyor Pop view denetleyicisi için çalışıyor
Mukul More

16

İçinde unutmayın Swift , uzatma kesinlikle arkadaşlardır!

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

Özel aramalar kullanmak kötü bir fikir çünkü Apple artık bunu yapan uygulamaları onaylamıyor. Belki bunu deneyebilirsiniz:

//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];

Sadece "yarım" işe yarıyor - pop animasyonların daha zor problemini çözmeyecek.
Adam

Bu çözümü daha çok seviyorum ve evet işe yarıyor. Özel yöntemler kullanmak sizi kesinlikle reddedecektir.
Benjamin Intal

Özel api çağrısı olan @nicktmro. Fark etmedim.
Franklin

@Franklin burada bir süre önce -pushViewController:transition:forceImmediate:kötü bir fikir olacak bir tartışma vardı .
nicktmro

9

Bu Google'daki en iyi sonuç olduğu için en aklı başında olduğunu düşündüğüm şeyi paylaşacağımı düşündüm; iOS 7+ geçiş API'sını kullanmaktır. Swift 3 ile iOS 10 için bunu uyguladım.

Bunu, UINavigationControllerbir sınıfın alt sınıfını oluşturursanız UINavigationControllerve bir sınıfınUIViewControllerAnimatedTransitioningProtokolle .

Örneğin benim UINavigationControlleralt sınıfım:

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

}

Kendine ayarladığımı görebilirsiniz UINavigationControllerDelegateve alt sınıfımdaki bir uzantıda, UINavigationControllerDelegateözel bir animasyon denetleyicisi (yani, NavigationControllerAnimation) döndürmenize izin veren yöntemi uygularım . Bu özel animasyon denetleyicisi sizin için stok animasyonunun yerini alacak.

Muhtemelen NavigationControllerAnimationbaşlatıcı aracılığıyla operasyona neden örneğe geçtiğimi merak ediyorsunuzdur . Bunu NavigationControllerAnimation,UIViewControllerAnimatedTransitioning (itme 'veya '' pop protokolü Ben operasyon yani) ne olduğunu biliyorum.' Bu ne tür bir animasyon yapmam gerektiğini bilmemize yardımcı olur. Çoğu zaman, işleme bağlı olarak farklı bir animasyon gerçekleştirmek istersiniz.

Gerisi oldukça standarttır. UIViewControllerAnimatedTransitioningProtokolde gerekli iki işlevi uygulayın ve istediğiniz gibi canlandırın:

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

Her farklı işlem türü için (yani, 'itme' veya 'pop) için görünümden ve görünümden denetleyicilerin farklı olacağını hatırlamak önemlidir. Bir itme işlemindeyken, görüntüleme denetleyicisi itilen kumanda olacaktır. Bir pop işlemindeyken, görünüm denetleyicisi, geçiş yapılan denetleyici, ve görünüm denetleyicisi de patlatılan denetleyici olacaktır.

Ayrıca, togörünüm denetleyicisi containerViewgeçiş bağlamında alt görünümü olarak eklenmelidir .

Animasyonunuz tamamlandığında aramalısınız transitionContext.completeTransition(true). Etkileşimli bir geçiş yapıyorsanız, dinamik bir geri dönmek zorunda kalacak Boolkadar completeTransition(didComplete: Bool)geçiş animasyon sonunda tamamlanıp tamamlanmadığını bağlı.

Son olarak ( isteğe bağlı okuma ), üzerinde çalıştığım geçişi nasıl yaptığımı görmek isteyebilirsiniz. Bu kod biraz daha hacky ve ben oldukça hızlı bir şekilde yazdım, bu yüzden harika bir animasyon kodu olduğunu söyleyemem ama yine de animasyon parçasının nasıl yapılacağını gösterir.

Benimki gerçekten basit bir geçişti; UINavigationController'ın yaptığı gibi aynı animasyonu taklit etmek istedim, ancak 'üstte bir sonraki sayfa' animasyonu yerine, yeni görünümle aynı anda eski görünüm denetleyicisinin 1: 1 animasyonunu uygulamak istedim denetleyici görünür. Bu, iki görünüm kontrolörünün birbirine sabitlenmiş gibi görünmesini sağlar.

İtme işlemi için, önce toViewControllerx ekseni kapalı ekranındaki görünümün başlangıcını ayarlamayı, alt görünümü olarak ekleyerek sıfıra containerViewayarlayarak ekranda canlandırmayı gerektirir origin.x. Aynı zamanda, ekranını kapatarak fromViewControllergörüntüsünü uzaklara hareket ettiriyorum origin.x:

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

Pop işlemi temelde tersidir. Ekle toViewControllerbir subview containerViewve uzak animasyon fromViewControllerİçinde animasyon olarak sağa toViewControllersoldan:

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

İşte tüm hızlı dosyanın bir özeti:

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


Harika!. Yapmak istediğim şey SADECE zıt yönde animasyon yapmak. Diğer bazı çözümleri inceledim, ancak hepsi sol ve sağ ekranda yanıp sönüyor. Örtülü alfa değişim animasyonu onlarla kaldırılamaz gibi görünüyor. Sadece bu çözüm sorunu düzeltti.
beshio

evet, bu tek doğru modern çözüm. (
Umrumda

@AlanZeino Ya aynı ViewController içinde farklı düğme tıklama için farklı animasyonlar olması gerekiyorsa? Bu nedenle, button1 için animasyonu çözmeniz gerekir, button2 için varsayılan geçiş gerekir.
jzeferino

7

Orada UINavigationControllerDelegate ve UIViewControllerAnimatedTransitioning istediğiniz herhangi bir şey için animasyon değiştirebilirsiniz.

Örneğin, bu VC için dikey pop animasyonu:

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

}

Ve sonra

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

Yararlı öğretici https://www.objc.io/issues/5-ios7/view-controller-transitions/


6

Dayanarak cevap hız için güncellenmiş 4jordanperry

İtmek için 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)
})

Pop için

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

Swift'te aynısını şu şekilde yaptım:

İtme için:

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

Pop için:

Bunu yukarıdaki tepkilerden biraz farklı yaptım - ama Swift gelişiminde yeni olduğum için doğru olmayabilir. Ben geçersiz kılındı viewWillDisappear:animated:ve pop kodu orada ekledi:

    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'nun Swift 4.2'deki cevabı

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

Son zamanlarda benzer bir şey yapmaya çalışıyordum. UINavigationController'ın kayan animasyonunu beğenmediğime karar verdim, ancak UIView'in size kıvrılma veya benzeri bir şey verdiği animasyonları da yapmak istemedim. İttiğimde veya pop yaptığımda görünümler arasında çapraz solma yapmak istedim.

Buradaki sorun, görünümün tam anlamıyla görünümü kaldırması veya geçerli olanın üstünden bir tane atmasıdır, bu yüzden bir solma işe yaramaz. Yeni görüşümü alıp UIViewController yığınındaki mevcut üst görünüme bir alt görünüm olarak eklemeye geldim. 0'lık bir alfa ile ekledim, sonra bir çapraz ifade yapıyorum. Animasyon dizisi bittiğinde, görünümü canlandırmadan yığının üzerine iterim. Daha sonra eski topView'e geri dönüp değiştirdiğim şeyleri temizledim.

Bundan biraz daha karmaşık, çünkü navigasyonunuz var Geçişin doğru görünmesini sağlamak için ayarlamanız gerekiyor. Ayrıca, herhangi bir döndürme yaparsanız, görünümleri alt görünüm olarak eklerken çerçeve boyutlarını ayarlamanız gerekir, böylece ekranda doğru şekilde görünürler. İşte kullandığım kodlardan bazıları. UINavigationController alt sınıfını ve push ve pop yöntemleri overrode.

-(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];

 }

Kodda bahsettiğim gibi, her zaman sol çubuk düğmesi öğesi var, bu yüzden animasyon temsilcisi için geçtiği diziye koymadan önce nil olup olmadığını kontrol etmiyorum. Bunu yaparsanız, bu kontrolü yapmak isteyebilirsiniz.

Bulduğum sorun, temsilci yönteminde hiç çöktüğünüzde, programın çökmemesiydi. Temsilcinin tamamlanmasını durdurur, ancak herhangi bir uyarı almazsınız.
Bu delege rutininde temizlik yaptığım için, temizliği bitirmediği için garip görsel davranışlara neden oluyordu.

Oluşturduğum geri düğmesi "goBack" yöntemini çağırıyor ve bu yöntem sadece pop rutinini çağırıyor.

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

Ayrıca, benim pop rutinim.

-(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];
    }


 }
}

Hepsi bukadar. Rotasyon uygulamak istiyorsanız ek bir koda ihtiyacınız olacaktır. Alt görünümler olarak eklediğiniz görünümlerinizin kare boyutunu ayarlamanız gerekir; aksi takdirde yönelimin yatay olduğu konularla karşılaşırsınız, ancak önceki görünümü en son gördüğünüzde dikeydir. Böylece, onu bir alt görünüm olarak ekleyip içeri sürüklersiniz, ancak portre olarak görünür, o zaman animasyon olmadan açtığımızda, aynı görünüm, ancak yığındaki olan şimdi manzaradır. Her şey biraz korkak görünüyor. Herkesin rotasyon uygulaması biraz farklı olduğundan kodumu buraya eklemedim.

Umarım bazı insanlara yardımcı olur. Her yerde böyle bir şey aradım ve hiçbir şey bulamadım. Bunun mükemmel bir cevap olduğunu düşünmüyorum, ama bu noktada benim için gerçekten iyi çalışıyor.


Takdire şayan olsa da, şimdi 7 yıl sonra bu dürüstçe çözüm değil!
Fattie

Haklısın. Bu cevap 2011'den geldi. O zamanlar işe yaradı, ama o zamandan beri işler çok değişti. =)
georryan

4

Şimdi kullanabilirsiniz UIView.transition. Unutmayın animated:false. Bu, herhangi bir geçiş seçeneği, pop, push veya yığın değiştirme ile çalışır.

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


3

İJordan'ın cevabını ilham olarak kullanarak, neden bu animasyon kodunu her yere kopyalamak / yapıştırmak yerine UINavigationController üzerinde bir Kategori oluşturmuyorsunuz?

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

Sonra sadece UINavigationController + Animation.h dosyasını içe aktarın ve normal olarak çağırın:

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

[self.navigationController popViewControllerWithFlip];

Zeki. Ama neden flipFromRight'a sabit kod yerine UIViewAnimationTransition argümanını alan push / pop yöntemleri eklemiyorsunuz?
Jef

@Jef bunlar kolaylık yöntemleridir - bu şekilde, uygulayıcının her bir belirli animasyon türü için hangi UIViewAnimationTransition değerinin iletileceğini hatırlaması gerekmez, sadece yöntemi gerçekleştirmek istediklerinin "ingilizce" adıyla çağırırlar.
DiscDev

@Jef ayrıca, öneriniz kesinlikle geçerlidir - hala objektif-c kullanıyordum ve birçok geçiş stilini desteklemem gerekiyorsa (birçok farklı geçiş stilinin kullanıcıları karıştırması tavsiye edilmez) UIViewAnimationTransition türünü alan 1 yöntemim olurdu, geliştirmeyi kolaylaştırmak için çeşitli kolaylık yöntemleri.
DiscDev

3

Çok basit

self.navigationController?.view.semanticContentAttribute = .forceRightToLeft

StackOverflow'a hoş geldiniz: kod, XML veya veri örnekleri gönderiyorsanız, lütfen metin düzenleyicide bu satırları vurgulayın ve düzenleyici araç çubuğundaki "kod örnekleri" düğmesini ({}) veya güzel biçimlendirmek için klavyenizdeki Ctrl + K tuşlarını tıklayın ve sözdizimi vurgulayın!
WhatsThePoint

2

Applidium'da oluşturduğumuz özel geçiş animasyonlarıyla (API'sı UINavigationController API'siyle eşleşir) UINavigationController'ın yerini alan bir damla olan ADTransitionController'a bir göz atın .

Sen farklı ön tanımlı animasyonlar kullanabilir itme ve pop gibi eylemler Swipe , Fade , Cube , Carrousel'de , Zum vb vb.


2

Buradaki tüm cevaplar harika ve çoğu çok iyi çalışıyor olsa da, aynı etkiyi sağlayan biraz daha basit bir yöntem var ...

İtme için:

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

Pop için:

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

Bu, kök görünüm denetleyicisine açılırken çökecektir.
Abdullah Umer

1

Geçiş animasyonunu herkese açık olarak değiştirmenin hiçbir yolunun farkında değilim.

"Geri" düğmesini gerekli değilse gerektiğini kullanmak modal görünümü denetleyicileri / "solma" / (≥3.2) "sayfa kıvrımı" geçişler / "kapak" "alt gelen itmek" için.


Açık özel tarafı, yöntem -pushViewController:animated:belgesiz yöntemini çağıran -pushViewController:transition:forceImmediate:ör böylece sol Flip-den-sağa geçiş, kullanabileceğiniz bir istiyorsanız,

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

Ancak "pop" geçişini bu şekilde değiştiremezsiniz.


1

Daha az kod satırında yapmanın bir yolu için bu soruya verdiğim cevaba bakın . Bu yöntem, yeni bir görünüm denetleyicisinin sözde "Push" u istediğiniz şekilde canlandırmanıza olanak tanır ve animasyon tamamlandığında, sanki standart Push yöntemini kullanmış gibi Gezinti Denetleyicisini ayarlar. Örneğim, bir slayt girişini soldan veya sağdan canlandırmanıza olanak tanır. Kolaylık olması için kod burada tekrarlanmıştır:

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

Örnek uygulamadan, bu varyasyona göz atın. 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

Sadece kullan:

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

Bunun farkına varmak eski bir sorudur. Bu cevabı hala göndermek istiyorum, çünkü viewControllersönerilen cevaplarla birkaç tane patlarken bazı problemlerim vardı . Benim çözümüm, UINavigationControllertüm pop ve push yöntemlerini alt sınıflara ayırmak ve geçersiz kılmak.

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

Bu iş parçasının eski olduğunu biliyorum, ama iki sentime koyacağımı düşündüm. Özel bir animasyon yapmanıza gerek yok, bunu yapmanın basit (belki de hileli) bir yolu var. Push'u kullanmak yerine, yeni bir gezinme denetleyicisi oluşturun, yeni görünüm denetleyicisini o gezinme denetleyicisinin kök görünüm denetleyicisi yapın ve sonra nav denetleyicisini orijinal gezinme denetleyicisinden sunun. Mevcut birçok stil ile kolayca özelleştirilebilir ve özel bir animasyon yapmaya gerek yoktur.

Örneğin:

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

Ve sunum stilini istediğiniz gibi değiştirebilirsiniz.


-1

Bunu yapmak için hafif bir özyinelemeli yol buldum. Ben normal haşhaş animasyon engellemek ve kendi animasyonsuz pop mesaj yerine kullanmak için kullandığım bir örnek değişken BOOL var. Değişken başlangıçta NO olarak ayarlanır. Geri düğmesine basıldığında, delege yöntemi bunu YES olarak ayarlar ve gezinme çubuğuna yeni bir animasyonsuz pop mesajı gönderir ve böylece aynı kez bu delege yöntemini YES olarak ayarlanmış olarak çağırır. Değişken YES olarak ayarlandığında, delege yöntemi bunu NO olarak ayarlar ve animasyonsuz pop oluşmasına izin vermek için YES değerini döndürür. İkinci delege çağrısı döndükten sonra, ilk animasyona geri döneriz, burada NO döndürülür, orijinal animasyon pop'u engeller! Aslında göründüğü kadar dağınık değil. ShouldPopItem yöntemim şöyle görünür:

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

Benim için çalışıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.