नेविगेशन आधारित ऐप में पुश और पॉप एनिमेशन कैसे बदलें


221

मेरे पास एक नेविगेशन आधारित एप्लिकेशन है और मैं पुश और पॉप एनिमेशन के एनीमेशन को बदलना चाहता हूं। मुझे यह कैसे करना है?

2018 संपादित करें

इस सवाल के कई जवाब हैं और अभी काफी समय हो गया है, मैंने इस उत्तर को फिर से चुन लिया है जो मुझे लगता है कि अब सबसे अधिक प्रासंगिक है। अगर कोई ऐसा है जो सोचता है तो कृपया मुझे टिप्पणियों में बताएं


25
IOS 7 के रूप में, इसके लिए आधिकारिक एपीआई है; देख UINavigationControllerDelegate के कस्टम संक्रमण एनीमेशन समर्थन करते हैं। इस बारे में एक WWDC 2013 वीडियो भी है ।
जेसी रसाक

मैंने स्विफ्ट में ऐसा करने के लिए एक उत्तर (नीचे) जोड़ा है - मैं इस सवाल के बारे में स्विफ्ट कार्यान्वयन के बारे में पूछ रहा हूं ताकि मुझे लगा कि मैं अपने बाद के कार्यान्वयन के साथ झंकार करूंगा।
djbp

1
आधिकारिक (iOS 7+) एपीआई के साथ एक बहुत अच्छे ट्यूटोरियल के लिए, देखें: bradbambara.wordpress.com/2014/04/11/…
nikolovski

1
@JesseRusak ने WWDC 2013 वीडियो के लिए लिंक अपडेट किया: डेवलपर
Wojciech Rutkowski

1
मेरे स्वीकार किए गए उत्तर दोस्तों n gals को बदल दिया। उम्मीद है की यह मदद करेगा! GLHF
Jab

जवाबों:


35

नेविगेशन आधारित ऐप में पुश और पॉप एनिमेशन कैसे बदलें ...

2019 के लिए, "अंतिम जवाब!"

प्रस्तावना:

कहते हैं कि आप iOS के विकास में नए हैं। भ्रामक रूप से, Apple दो संक्रमण प्रदान करता है जो आसानी से उपयोग किए जा सकते हैं। ये हैं: "क्रॉसफ़ेड" और "फ्लिप"।

लेकिन निश्चित रूप से, "क्रॉसफ़ेड" और "फ्लिप" बेकार हैं। इनका कभी उपयोग नहीं किया जाता है। कोई नहीं जानता कि Apple ने उन दो बेकार संक्रमणों को क्यों प्रदान किया!

इसलिए:

कहें कि आप एक सामान्य, सामान्य, संक्रमण जैसे "स्लाइड" करना चाहते हैं। उस मामले में, आपको एक बड़ी मात्रा में काम करना होगा!

वह काम, इस पोस्ट में बताया गया है।

बस दोहराने के लिए:

हैरानी की बात है: iOS के साथ, यदि आप सबसे सरल, सबसे आम, हर रोज़ संक्रमण (जैसे एक साधारण स्लाइड) चाहते हैं, तो आपको एक पूर्ण कस्टम संक्रमण लागू करने के सभी काम करने होंगे ।

यहाँ यह कैसे करना है ...

1. आपको एक कस्टम की जरूरत है UIViewControllerAnimatedTransitioning

  1. आपको अपनी तरह का एक बूल चाहिए popStyle। (क्या यह पॉपिंग है, या पॉपिंग है?)

  2. आपको transitionDuration(तुच्छ) और मुख्य कॉल शामिल करना चाहिए ,animateTransition

  3. वास्तव में आप चाहिए अंदर के लिए दो अलग-अलग दिनचर्या लिखना animateTransition। एक धक्का के लिए, और एक पॉप के लिए। शायद उनका नाम animatePushऔर animatePop। अंदर animateTransition, बस popStyleदो दिनचर्या पर शाखा

  4. नीचे दिया गया उदाहरण एक सरल चाल-ओवर / चाल-चलन है

  5. अपने animatePushऔर animatePopदिनचर्या में। आपको "दृश्य से" और "देखने के लिए" प्राप्त करना होगा । (ऐसा कैसे करें, कोड उदाहरण में दिखाया गया है।)

  6. और आपको नए "से" दृश्य के लिए होना चाहिए addSubview

  7. और आपको अपने मोबाइल फोनों के अंत में कॉल करना होगाcompleteTransition

इसलिए ..

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

और तब ...

2. अपने व्यू कंट्रोलर में इसका इस्तेमाल करें।

नोट: अजीब तरह से, आपको केवल "पहले" दृश्य नियंत्रक में ऐसा करना होगा । (जो "नीचे" है)

एक के साथ कि आप शीर्ष पर पॉप करते हैं, कुछ भी नहीं करते हैं । आसान।

तो आपकी कक्षा ...

class SomeScreen: UIViewController {
}

हो जाता है ...

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

बस।

पुश और पॉप बिल्कुल सामान्य, कोई बदलाव नहीं। धक्का मारना ...

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

और इसे पॉप करने के लिए, आप चाहें तो अगली स्क्रीन पर ऐसा कर सकते हैं:

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

ओह।


3. इस पृष्ठ पर अन्य उत्तरों का भी आनंद लें, जो बताते हैं कि एनिमेटेडट्रेटट्रिशनिंग को कैसे ओवरराइड किया जाए

AnimatedTransitioningIOS ऐप में इन दिनों अधिक चर्चा के लिए @AlanZeino और @elias उत्तर पर स्क्रॉल करें !


अति उत्कृष्ट! अगर मैं चाहता हूँ कि नेविगेशन स्वाइप बैक जेस्चर एक ही AnimatedTransitioning को भी सपोर्ट करे। कोई उपाय?
सैम ची वेन

धन्यवाद @samchiwen - वास्तव में यही है animatePushऔर क्या animatePopहैं .. दो अलग-अलग दिशाएँ!
फेटी

268

मैंने निम्नलिखित किया और यह ठीक काम करता है .. और सरल और समझने में आसान है ..

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

और धक्का के लिए एक ही बात ..


स्विफ्ट 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, यह वास्तव में सबसे अधिक समाधान है। भविष्य के आगंतुकों के लिए बस एक मामूली नोट: Animated:NOहिस्सा महत्वपूर्ण है। यदि YESपारित किया जाता है, तो एनिमेशन मिश्रित होते हैं और मजाकिया प्रभाव पैदा करते हैं।
DarkDust

12
अब तक का सबसे अच्छा समाधान .. और शुरुआती लोगों के लिए, QuartCore (#import <QuartzCore / QuartzCore.h>) को शामिल करना न भूलें
nomann

4
मेरे पास इस समस्या के साथ एकमात्र समस्या यह है कि धक्का दिए जाने के बाद मैं इसे बिना एनीमेशन के धकेलने के तुरंत बाद देखने वाले की नजर में आता है। क्या इसके आसपास कोई रास्ता है?
पेड्रो मैनचेनो

9
इस कोड के साथ मेरा मुद्दा यह है कि जब वे अंदर या बाहर स्लाइड करते हैं तो प्रत्येक दृश्य ग्रे या सफ़ेद दिखाई देता है।
क्रिस

1
iOS 7.1.2 और iOS 8.3 पर चेक किया गया - यह कोड विधि के लिए भी ठीक काम कर रहा हैsetViewControllers:
proff

256

इस तरह मैंने हमेशा इस कार्य को पूरा करने में कामयाबी हासिल की है।

पुश के लिए:

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

पॉप के लिए:

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


मुझे अभी भी इस से बहुत अधिक प्रतिक्रिया मिल रही है इसलिए मैं आगे बढ़ने जा रहा हूं और एनीमेशन ब्लॉक का उपयोग करने के लिए इसे अपडेट कर रहा हूं जो कि Apple वैसे भी एनिमेशन करने के लिए अनुशंसित तरीका है।

पुश के लिए:

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

पॉप के लिए:

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

3
इसके लिए धन्यवाद। लेकिन पॉप UINavigationController द्वारा स्वचालित रूप से किया जाता है। आप उस व्यवहार को कैसे ओवरराइड करते हैं ताकि आप अपने कस्टम पॉप लॉजिक को बुला सकें?
जोशुआ फ्रैंक

1
@stuckj वास्तव में यह काम करता है !!! तुम सिर्फ बदलने के लिए superद्वाराself.navigationController
holierthanthou84

क्या दाईं ओर से डिफ़ॉल्ट स्लाइड के बजाय बाईं ओर से स्लाइड प्राप्त करने का कोई तरीका है?
शिम

पहला नया दृश्य बिल्कुल नहीं दिखाता है। दूसरा एनीमेशन नहीं दिखाता है। बहुत बुरा जवाब! iOS 7.
दिमित्री

2
आपने UIViewController"ViewController" भाग के बिना एक नाम को उपवर्गित करने के लिए क्यों प्राप्त किया है यह नाम UIView के लिए अधिक उपयुक्त है।
user2159978

29

धक्का देने के लिए

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

पॉप के लिए

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

@ मैग्नस का जवाब, तभी स्विफ्ट (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)

कुछ कटाक्ष:

आप सेग के साथ भी ऐसा कर सकते हैं, बस इसे prepareForSegueया में लागू करें shouldPerformSegueWithIdentifierतथापि , यह इसमें डिफ़ॉल्ट एनीमेशन को भी रखेगा। इसे ठीक करने के लिए आपको स्टोरीबोर्ड पर जाना होगा, सेगू पर क्लिक करना होगा और बॉक्स 'एनिमेट्स' को अनचेक करना होगा। लेकिन यह आपके ऐप को IOS 9.0 और उससे अधिक के लिए सीमित कर देगा (कम से कम जब मैंने इसे Xcode 7 में किया था)।

जब एक सेग में कर रहे हों, तो अंतिम दो पंक्तियों को प्रतिस्थापित किया जाना चाहिए:

self.navigationController?.popViewControllerAnimated(false)

भले ही मैं गलत सेट करता हूं, यह इसे अनदेखा करता है।


एनीमेशन के अंत में पृष्ठभूमि में काले रंग को कैसे हटाया जाए।
मधु

पॉप व्यू कंट्रोलर के लिए पुश व्यू कंट्रोलर एनीमेशन काम नहीं करता है
मुकुल मोर

16

याद रखें कि स्विफ्ट में , विस्तार निश्चित रूप से आपके दोस्त हैं!

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

निजी कॉल का उपयोग करना एक बुरा विचार है क्योंकि Apple अब ऐसा करने वाले ऐप्स को अनुमोदित नहीं करता है। शायद आप यह कोशिश कर सकते हैं:

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

यह केवल "आधा" काम करता है - यह पॉप एनिमेशन की कठिन समस्या को हल नहीं करेगा।
एडम

मुझे यह समाधान बेहतर लगता है, और हाँ यह काम करता है। निजी विधियों का उपयोग करना आपको सुनिश्चित करने के लिए अस्वीकृत कर देगा।
बेंजामिन इंटल

@nicktmro जो कि निजी एपि कॉल है। मैंने कोई नोटिस नहीं किया।
फ्रैंकलिन

@ फ्रेंकलिन कुछ समय पहले यहां चर्चा कर रहे थे कि -pushViewController:transition:forceImmediate:कौन सा प्रयोग बुरा होगा।
निकल्ट्रो

9

चूँकि यह Google पर शीर्ष परिणाम है, मैंने सोचा कि मैं जो सबसे अधिक समझदार तरीका है उसे साझा करूँगा; जो iOS 7+ ट्रांस्फ़ॉर्मिंग API का उपयोग करने के लिए है। मैंने इसे स्विफ्ट 3 के साथ iOS 10 के लिए लागू किया।

UINavigationControllerयदि आप एक उप-वर्ग बनाते हैं UINavigationControllerऔर UIViewControllerAnimatedTransitioningप्रोटोकॉल के अनुरूप होते हैं तो उस वर्ग का एक उदाहरण लौटाते हैं, जिसे दो दृश्य नियंत्रकों के बीच कैसे एनिमेट किया जाता है, इसे संयोजित करना बहुत सरल है ।

उदाहरण के लिए यहाँ मेरा UINavigationControllerउपवर्ग है:

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

}

आप देख सकते हैं कि मैंने UINavigationControllerDelegateखुद को सेट किया है, और मेरे उपवर्ग पर विस्तार में मैं उस पद्धति को लागू करता हूं UINavigationControllerDelegateजिससे आप एक कस्टम एनीमेशन नियंत्रक (यानी, NavigationControllerAnimation) को वापस कर सकते हैं । यह कस्टम एनीमेशन कंट्रोलर आपके लिए स्टॉक एनीमेशन को बदल देगा।

आप शायद सोच रहे हैं कि मैं ऑपरेशन में NavigationControllerAnimationइसके इनिशलाइज़र के माध्यम से क्यों गुजरता हूं । मैं ऐसा इसलिए करता हूं कि प्रोटोकॉल के NavigationControllerAnimationकार्यान्वयन में UIViewControllerAnimatedTransitioningमुझे पता है कि ऑपरेशन क्या है (यानी, 'पुश' या 'पॉप')। इससे यह जानने में मदद मिलती है कि मुझे किस तरह का एनीमेशन करना चाहिए। अधिकांश समय, आप ऑपरेशन के आधार पर एक अलग एनीमेशन करना चाहते हैं।

बाकी बहुत मानक है। UIViewControllerAnimatedTransitioningप्रोटोकॉल और चेतन में दो आवश्यक कार्यों को लागू करें, लेकिन आप जैसे हैं:

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

यह याद रखना महत्वपूर्ण है कि प्रत्येक अलग प्रकार के ऑपरेशन के लिए (जैसे, 'पुश' या 'पॉप), से और देखने के लिए नियंत्रक अलग-अलग होंगे। जब आप एक पुश ऑपरेशन में होते हैं, तो नियंत्रक को देखने के लिए धक्का दिया जाएगा। जब आप किसी पॉप ऑपरेशन में होते हैं, तो कंट्रोलर देखने वाला वह होगा जिसे संक्रमण किया जा रहा है, और व्यू कंट्रोलर वह होगा जो पॉपप हो रहा है।

इसके अलावा, संक्रमण के संदर्भ में toदृश्य नियंत्रक को उप-भाग के रूप में जोड़ा जाना चाहिए containerView

जब आपका एनीमेशन पूरा हो जाता है, तो आपको कॉल करना होगा transitionContext.completeTransition(true)। आप एक इंटरैक्टिव संक्रमण कर रहे हैं, तो आप गतिशील रूप से एक वापस करने के लिए करना होगा Boolकरने के लिए completeTransition(didComplete: Bool)संक्रमण एनीमेशन के अंत में पूरा हो गया है, तो के आधार पर,।

अंत में ( वैकल्पिक पठन ), आप यह देखना चाहते होंगे कि मैंने जिस संक्रमण पर काम कर रहा था, उसे कैसे किया। यह कोड थोड़ा अधिक हैकी है और मैंने इसे बहुत जल्दी लिखा है इसलिए मैं इसे महान एनीमेशन कोड नहीं कहूँगा लेकिन यह अभी भी दिखाता है कि एनीमेशन भाग को कैसे करना है।

मेरा एक बहुत ही सरल संक्रमण था; मैं उसी एनीमेशन की नकल करना चाहता था जो UINavigationController आम तौर पर करता है, लेकिन इसके बजाय 'अगला पृष्ठ ओवर द टॉप' एनीमेशन करता है, मैं पुराने दृश्य नियंत्रक के 1: 1 एनीमेशन को उसी समय लागू करना चाहता था जैसे कि नया दृश्य नियंत्रक प्रकट होता है। इससे दो दृश्य नियंत्रकों के रूप में ऐसा प्रतीत होता है कि जैसे वे एक दूसरे के लिए पिन किए जाते हैं।

पुश ऑपरेशन के लिए, जिसे toViewControllerस्क्रीन के x- अक्ष पर मूल दृश्य को सेट करने की आवश्यकता होती है , इसे सब-वे के रूप में जोड़कर containerView, इसे origin.xशून्य पर सेट करके स्क्रीन पर एनिमेट कर रहा है। उसी समय, मैं स्क्रीन को बंद fromViewControllerकरके दृश्य को दूर करता हूं 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)
})

पॉप ऑपरेशन मूल रूप से उलटा है। जोड़े toViewControllerकी एक subview के रूप containerViewहै, और दूर चेतन fromViewControllerसही करने के लिए के रूप में आप में चेतन toViewControllerबाएं से:

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

यहाँ पूरी स्विफ्ट फ़ाइल के साथ एक जिस्ट है:

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


महान!। मैं जो करना चाहता था, वह है विपरीत दिशा में चेतन करना। मैंने कुछ अन्य समाधानों की जांच की, लेकिन सभी बाएं और दाएं स्क्रीन पर चमकते दिखाई देते हैं। ऐसा लगता है कि अंतर्निहित अल्फा परिवर्तन एनीमेशन को उनके साथ नहीं हटाया जा सकता है। केवल इस समाधान ने समस्या को ठीक कर दिया।
बेशियो

हाँ, यह एकमात्र सही आधुनिक समाधान है। (मुझे कोई आपत्ति नहीं है, लेकिन यह बिल्कुल वैसा ही है जैसा कि मैंने नीचे टाइप किया हुआ समाधान! :))
Fattie

@AlanZeino क्या होगा अगर एक ही ViewController के अंदर आपको अलग-अलग बटन क्लिक के लिए diferente एनिमेशन की आवश्यकता है? तो, बटन 1 के लिए आपको एक भंग एनीमेशन की आवश्यकता है, बटन 2 के लिए आपको डिफ़ॉल्ट संक्रमण की आवश्यकता है।
jzeferino

7

वहाँ UINavigationControllerDelegate और UIViewControllerAnimatedTransitioning हैं, आप कुछ भी आप चाहते हैं के लिए एनीमेशन बदल सकते हैं।

उदाहरण के लिए यह 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())
    })
}

}

और तब

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

उपयोगी ट्यूटोरियल https://www.objc.io/issues/5-ios7/view-controller-transitions/


6

स्विफ्ट 4 के लिए अपडेट किए गए उत्तर के आधार परjordanperry

धक्का देने के लिए 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)
})

पॉप के लिए

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

यहाँ मैंने स्विफ्ट में ऐसा ही किया है:

पुश के लिए:

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

पॉप के लिए:

मैंने वास्तव में उपरोक्त कुछ प्रतिक्रियाओं के लिए यह थोड़ा अलग किया था - लेकिन जैसा कि मैं स्विफ्ट विकास के लिए नया हूं, यह सही नहीं हो सकता है। मैंने ओवरराइड किया है viewWillDisappear:animated:और वहां पॉप कोड जोड़ा है:

    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

स्विफ्ट 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

मैं हाल ही में कुछ ऐसा ही करने की कोशिश कर रहा था। मैंने फैसला किया कि मुझे UINavigationController का स्लाइडिंग एनीमेशन पसंद नहीं आया, लेकिन मैं यह भी नहीं करना चाहता था कि UIView आपको कर्ल या ऐसा कुछ भी देता है। जब मैं पुश या पॉप करता हूं तो मैं दृश्यों के बीच एक क्रॉस फीका करना चाहता था।

इस समस्या में यह तथ्य शामिल है कि दृश्य शाब्दिक रूप से दृश्य को हटा रहा है या वर्तमान के शीर्ष पर एक पॉपिंग कर रहा है, इसलिए एक फीका काम नहीं करता है। इसका हल मुझे अपने नए दृश्य को शामिल करने और इसे UIViewController के स्टैक पर वर्तमान शीर्ष दृश्य के लिए एक सबव्यू के रूप में शामिल करने के लिए आया था। मैं इसे 0 के अल्फा के साथ जोड़ता हूं, फिर एक क्रॉसफेड ​​करता हूं। जब एनीमेशन अनुक्रम समाप्त हो जाता है, तो मैं इसे बिना एनिमेशन के स्टैक पर देखने को धक्का देता हूं। मैं फिर पुराने topView पर वापस जाता हूं और उस सामान को साफ करता हूं जिसे मैंने बदला था।

इसकी तुलना में यह थोड़ा अधिक जटिल है, क्योंकि आपके पास नेविगेशन है। आपको संक्रमण को सही दिखने के लिए समायोजित करना होगा। इसके अलावा, यदि आप कोई रोटेशन करते हैं, तो आपको फ्रेम साइज को एडजस्ट करना होगा क्योंकि आप व्यूज को सब-टेस्ट के रूप में जोड़ते हैं ताकि वे स्क्रीन पर सही तरीके से दिखें। यहाँ कुछ कोड का उपयोग किया गया है। मैंने UINavigationController को उपविभाजित किया और पुश और पॉप विधियों को ओवररोड किया।

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

 }

जैसा कि मैंने कोड में उल्लेख किया है, मेरे पास हमेशा एक बाईं बार बटन आइटम है, इसलिए मैं यह देखने के लिए जांच नहीं करता हूं कि क्या यह सरणी में डालने से पहले शून्य है कि मैं एनीमेशन प्रतिनिधि के लिए संदर्भ के रूप में पास करता हूं। यदि आप ऐसा करते हैं, तो आप उस चेक को बनाना चाह सकते हैं।

जो समस्या मुझे मिली वह यह थी कि यदि आप प्रतिनिधि पद्धति में सभी पर क्रैश करते हैं, तो यह प्रोग्राम को क्रैश नहीं करेगा। यह प्रतिनिधि को पूरा करने से रोकता है लेकिन आपको किसी प्रकार की चेतावनी नहीं मिलती है।
इसलिए जब से मैं उस प्रतिनिधि दिनचर्या में अपना सफाई कर रहा था, तब से यह कुछ अजीब दृश्य व्यवहार पैदा कर रहा था क्योंकि यह सफाई को खत्म नहीं कर रहा था।

मेरे द्वारा बनाया गया बैक बटन कॉल को एक "goBack" विधि कहता है, और यह विधि सिर्फ पॉप रूटीन कहलाती है।

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

इसके अलावा, यहां मेरी पॉप दिनचर्या है।

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


 }
}

तो इतना ही है। यदि आप घुमाव लागू करना चाहते हैं तो आपको कुछ अतिरिक्त कोड की आवश्यकता होगी। आपको अपने विचारों के फ़्रेम का आकार निर्धारित करने की आवश्यकता होगी, जिन्हें आप साक्षात्कार के रूप में जोड़ते हैं, इससे पहले कि आप उन्हें दिखाएं अन्यथा आप उन मुद्दों में भाग लेंगे जो उन्मुखीकरण परिदृश्य है, लेकिन पिछली बार जब आपने पिछला दृश्य देखा था तो यह चित्र था। तो, फिर आप इसे एक उप दृश्य के रूप में जोड़ते हैं और इसे फीका करते हैं लेकिन यह चित्र के रूप में दिखाई देता है, फिर जब हम एनीमेशन के बिना पॉप करते हैं, तो वही दृश्य, लेकिन वह जो स्टैक में है, अब परिदृश्य है। पूरी बात थोड़ी फंकी लग रही है। हर किसी के रोटेशन का कार्यान्वयन थोड़ा अलग है, इसलिए मैंने उस के लिए अपना कोड यहां शामिल नहीं किया है।

आशा है कि यह कुछ लोगों की मदद करता है। मैं इस तरह से कुछ के लिए सब कुछ देखा है और कुछ भी नहीं मिल सकता है। मुझे नहीं लगता कि यह सही उत्तर है, लेकिन यह इस बिंदु पर मेरे लिए अच्छा काम कर रहा है।


जब तक सराहनीय, यह ईमानदारी से समाधान नहीं है अब 7 साल बाद!
फेटी

तुम सही हो। यह उत्तर 2011 से था। इसने तब वापस काम किया, लेकिन तब से चीजें बहुत बदल गई हैं। =)
जियोरीयन

4

अब आप उपयोग कर सकते हैं UIView.transition। ध्यान दें animated:false। यह किसी भी संक्रमण विकल्प, पॉप, पुश या स्टैक रिप्लेस के साथ काम करता है।

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

1
@Fattie, इस विशेष विधि केवल में सूचीबद्ध मानक इस तरह flips और कर्ल के रूप में एनिमेशन से किसी के साथ काम करता है developer.apple.com/documentation/uikit/uiviewanimationoptions
पीटर DeWeese

3

प्रेरणा के रूप में iJordan के उत्तर का उपयोग करते हुए, सभी स्थानों पर इस एनीमेशन कोड को कॉपी / पेस्ट करने के बजाय अपने एप्लिकेशन में उपयोग करने के लिए केवल UINavigationController पर एक श्रेणी क्यों नहीं बनाएं?

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

तो बस UINavigationController + Animation.h फ़ाइल आयात करें और इसे सामान्य रूप से कॉल करें:

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

[self.navigationController popViewControllerWithFlip];

चतुर। लेकिन पुश / पॉप तरीकों को क्यों नहीं जोड़ा गया है जो कि फ्लिपफ्रेम के लिए हार्डकोड के बजाय UIViewAnimationTransition का तर्क देता है?
Jef

@Jef ये सुविधा विधियाँ हैं - इस प्रकार, कार्यान्वयनकर्ता को यह याद रखने की आवश्यकता नहीं है कि प्रत्येक विशिष्ट एनीमेशन प्रकार के लिए उत्तीर्ण करने के लिए कौन सा UIViewAnimationTransition मान है, वे बस उस विधि को "अंग्रेज़ी" नाम से पुकारते हैं जिसे वे पूरा करना चाहते हैं।
डिस्कोदेव

@Jef भी, आपका सुझाव निश्चित रूप से मान्य है - अगर मैं अभी भी उद्देश्य-सी का उपयोग कर रहा था और कई संक्रमण शैलियों का समर्थन करने की आवश्यकता थी (निश्चित रूप से कई अलग-अलग संक्रमण शैलियों का उपयोग उपयोगकर्ताओं को भ्रमित नहीं करेगा) मेरे पास 1 तरीका होगा जो UIViewAnimationTitition प्रकार लेता है, फिर विकास को आसान बनाने के लिए कई सुविधा विधियाँ।
डिस्कोदेव

3

यह बहुत सरल है

self.navigationController?.view.semanticContentAttribute = .forceRightToLeft

StackOverflow में आपका स्वागत है: यदि आप कोड, XML या डेटा नमूने पोस्ट करते हैं, तो कृपया टेक्स्ट एडिटर में उन पंक्तियों को हाइलाइट करें और एडिटर टूलबार पर "कोड नमूने" बटन ({}) पर क्लिक करें या अपने कीबोर्ड पर Ctrl + K का उपयोग करके अच्छी तरह से फॉर्मेट करें। और वाक्य रचना इसे उजागर!
WhatsThePoint

2

ADTransitionController पर एक नज़र डालें , कस्टम ट्रांजिशन एनिमेशन के साथ UINavigationController के प्रतिस्थापन में एक बूंद (इसकी एपीआई UINavigationController के एपीआई से मेल खाती है) जिसे हमने Applidium में बनाया था।

आप पुश और पॉप कार्यों जैसे कि स्वाइप , फेड , क्यूब , कैरोसेल , जूम इत्यादि के लिए विभिन्न पूर्व-परिभाषित एनिमेशन का उपयोग कर सकते हैं ।


2

जबकि यहाँ सभी उत्तर बहुत अच्छे हैं और अधिकांश काम बहुत अच्छे हैं, थोड़ा सरल तरीका है जो समान प्रभाव प्राप्त करता है ...

पुश के लिए:

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

पॉप के लिए:

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

जब पॉप व्यू कंट्रोलर को पॉपिंग करना होगा तो यह क्रैश हो जाएगा।
अब्दुल्ला उमर

1

मुझे ऐसे किसी भी तरीके की जानकारी नहीं है जिससे आप सार्वजनिक रूप से ट्रांस्फ़ॉर्मेशन एनीमेशन बदल सकते हैं।

यदि "बैक" बटन आवश्यक नहीं है, तो आपको "नीचे से पुश" / "फ्लिप" / "फीका" / (≥3.2) "पेज कर्ल" संक्रमण के लिए मोडल व्यू कंट्रोलर का उपयोग करना चाहिए


पर निजी पक्ष, विधि -pushViewController:animated:गैर-दस्तावेजी प्रणाली को बुलाती है -pushViewController:transition:forceImmediate:, तो उदाहरण के लिए यदि आप एक फ्लिप से-बाएँ-से-दाएँ संक्रमण, आप उपयोग कर सकते हैं चाहते हैं

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

हालाँकि, आप "पॉप" संक्रमण को इस तरह नहीं बदल सकते।


1

इस प्रश्न के लिए मेरे उत्तर को कोड की कम लाइनों में करने के तरीके के लिए देखें । यह विधि आपको किसी भी तरह से एक नए दृश्य नियंत्रक के छद्म "पुश" को चेतन करने की अनुमति देती है, और जब एनीमेशन किया जाता है तो यह नेविगेशन नियंत्रक को उसी तरह सेट करता है जैसे कि आपने मानक पुश विधि का उपयोग किया था। मेरा उदाहरण आपको बाईं ओर या दाईं ओर से स्लाइड को चेतन करने देता है। सुविधा के लिए यहां दोहराया गया कोड:

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

नमूना ऐप से, इस भिन्नता की जाँच करें। 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

महज प्रयोग करें:

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

इसे साकार करना एक पुराना प्रश्न है। मैं अभी भी इस उत्तर को पोस्ट करना चाहूंगा, क्योंकि मुझे viewControllersप्रस्तावित उत्तरों के साथ कई पॉपिंग करने में कुछ समस्याएं थीं । मेरा समाधान UINavigationControllerसभी पॉप और पुश विधियों को उपवर्ग और ओवरराइड करना है।

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

मुझे पता है कि यह धागा पुराना है, लेकिन मुझे लगा कि मैं अपने दो सेंट में डालूंगा। आपको एक कस्टम एनीमेशन बनाने की आवश्यकता नहीं है, इसे करने का एक सरल (शायद हैकी) तरीका है। पुश का उपयोग करने के बजाय, एक नया नेविगेशन कंट्रोलर बनाएं, नए व्यू कंट्रोलर को उस नेवी कंट्रोलर के रूट व्यू कंट्रोलर बनाएं और फिर नेवी कंट्रोलर को ओरिजिनल नेवी कंट्रोलर से प्रेजेंट करें। वर्तमान कई शैलियों के साथ आसानी से अनुकूलन योग्य है, और कस्टम एनीमेशन बनाने की कोई आवश्यकता नहीं है।

उदाहरण के लिए:

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

और यदि आप चाहते हैं, तो आप प्रस्तुति शैली को बदल सकते हैं।


-1

मुझे ऐसा करने के लिए एक हल्का पुनरावर्ती तरीका मिला जो मेरे उद्देश्यों के लिए काम करता है। मेरे पास एक उदाहरण चर BOOL है जो मैं सामान्य पॉपिंग एनीमेशन को ब्लॉक करने के लिए उपयोग करता हूं और अपने स्वयं के गैर-एनिमेटेड पॉप संदेश को प्रतिस्थापित करता हूं। चर को शुरू में NO पर सेट किया जाता है। जब बैक बटन टैप किया जाता है, तो प्रतिनिधि विधि इसे YES पर सेट करती है और नेव बार में एक नया गैर-एनिमेटेड पॉप संदेश भेजता है, जिससे उसी प्रतिनिधि विधि को फिर से कॉल किया जाता है, इस बार YES के लिए सेट किए गए चर के साथ। चर के साथ YES पर सेट है, प्रतिनिधि विधि इसे NO पर सेट करता है और गैर-एनिमेटेड पॉप होने की अनुमति देने के लिए YES देता है। दूसरे प्रतिनिधि कॉल रिटर्न के बाद, हम पहले एक में वापस आ जाते हैं, जहाँ NO वापस नहीं आता है, मूल एनिमेटेड पॉप को अवरुद्ध करता है! यह वास्तव में उतना गन्दा नहीं है जितना यह लगता है। इस तरह दिखना चाहिए

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

मेरे लिये कार्य करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.