RootViewController स्विच संक्रमण एनीमेशन


125

AppDelegate में किसी नए के साथ मौजूदा व्यू कॉन्ट्रैक्टर को rootviewcontroller के रूप में बदलने के दौरान संक्रमण / एनीमेशन प्रभाव होने का कोई तरीका है?

जवाबों:


272

आप rootViewControllerएक संक्रमण एनीमेशन ब्लॉक में स्विचिंग को लपेट सकते हैं :

[UIView transitionWithView:self.window
                  duration:0.5
                   options:UIViewAnimationOptionTransitionFlipFromLeft
                animations:^{ self.window.rootViewController = newViewController; }
                completion:nil];

5
हे ओले, मैंने इस दृष्टिकोण की कोशिश की, यह आंशिक रूप से काम करता है, बात यह है कि मेरा ऐप केवल लैंडस्केप मोड में रहेगा, लेकिन रूटव्यूकंट्रोलर ट्रांजिशन करने से, नव-प्रस्तुत दृश्य नियंत्रक शुरुआत में पोर्ट्रेट में लोड होता है, और जल्दी से लैंडस्केप मोड में घूमता है। , कैसे हल करने के लिए?
क्रिस चेन

4
मैंने क्रिस चेन के सवाल का जवाब दिया (उम्मीद है! शायद) अपने अलग सवाल में यहां: stackoverflow.com/questions/8053832/…
कलल

1
हे मैं एक एनीमेशन में एक धक्का संक्रमण चाहते हैं कि मैं प्राप्त कर सकते हैं?
उपयोगकर्ता 1531343

14
मैं इस के साथ कुछ मुद्दों पर ध्यान दिया है, अर्थात् गलत तत्वों / आलसी लोड तत्वों। उदाहरण के लिए, यदि आपके पास मौजूदा रूट vc पर एक नेविगेशन बार नहीं है, तो एक नए vc में चेतन करें जिसमें एक है, एनीमेशन पूरा हो जाता है और फिर नेन बार जोड़ा जाता है। यह थोड़े नासमझ लग रहा है - यह क्यों हो सकता है, और क्या किया जा सकता है पर कोई विचार?
अनोन_देव 1234

1
मैंने पाया है कि newViewController.view.layoutIfNeeded()एनीमेशन ब्लॉक से पहले कॉल करने से आलसी-लोडेड तत्वों के साथ समस्याएं ठीक हो जाती हैं।
वाह

66

मैंने यह पाया और पूरी तरह से काम करता है:

अपने appDelegate में:

- (void)changeRootViewController:(UIViewController*)viewController {

    if (!self.window.rootViewController) {
        self.window.rootViewController = viewController;
        return;
    }

    UIView *snapShot = [self.window snapshotViewAfterScreenUpdates:YES];

    [viewController.view addSubview:snapShot];

    self.window.rootViewController = viewController;

    [UIView animateWithDuration:0.5 animations:^{
        snapShot.layer.opacity = 0;
        snapShot.layer.transform = CATransform3DMakeScale(1.5, 1.5, 1.5);
    } completion:^(BOOL finished) {
        [snapShot removeFromSuperview];
    }];
}

आपके ऐप में

 if (!app) { app = (AppDelegate *)[[UIApplication sharedApplication] delegate]; }
        [app changeRootViewController:newViewController];

क्रेडिट:

https://gist.github.com/gimenete/53704124583b5df3b407


क्या यह ऑटो स्क्रीन को घुमाती है?
विंग्जेरो

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

@Wingzero थोड़ी देर से, लेकिन, यह किसी भी प्रकार के संक्रमण की अनुमति देगा, या तो UIView.animations (जैसे, CGAffineTransform को घुमाने के लिए) या कस्टम CAAnimation के माध्यम से।
Can

41

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

स्विफ्ट 3.0 अपडेट:

  func changeRootViewController(with identifier:String!) {
    let storyboard = self.window?.rootViewController?.storyboard
    let desiredViewController = storyboard?.instantiateViewController(withIdentifier: identifier);

    let snapshot:UIView = (self.window?.snapshotView(afterScreenUpdates: true))!
    desiredViewController?.view.addSubview(snapshot);

    self.window?.rootViewController = desiredViewController;

    UIView.animate(withDuration: 0.3, animations: {() in
      snapshot.layer.opacity = 0;
      snapshot.layer.transform = CATransform3DMakeScale(1.5, 1.5, 1.5);
      }, completion: {
        (value: Bool) in
        snapshot.removeFromSuperview();
    });
  }

स्विफ्ट 2.2 अपडेट:

  func changeRootViewControllerWithIdentifier(identifier:String!) {
    let storyboard = self.window?.rootViewController?.storyboard
    let desiredViewController = storyboard?.instantiateViewControllerWithIdentifier(identifier);

    let snapshot:UIView = (self.window?.snapshotViewAfterScreenUpdates(true))!
    desiredViewController?.view.addSubview(snapshot);

    self.window?.rootViewController = desiredViewController;

    UIView.animateWithDuration(0.3, animations: {() in
      snapshot.layer.opacity = 0;
      snapshot.layer.transform = CATransform3DMakeScale(1.5, 1.5, 1.5);
      }, completion: {
        (value: Bool) in
        snapshot.removeFromSuperview();
    });
  }

  class func sharedAppDelegate() -> AppDelegate? {
    return UIApplication.sharedApplication().delegate as? AppDelegate;
  }

के बाद, आप कहीं से भी बहुत सरल उपयोग कर सकते हैं:

let appDelegate = AppDelegate.sharedAppDelegate()
appDelegate?.changeRootViewControllerWithIdentifier("YourViewControllerID")

स्विफ्ट 3.0 अपडेट

let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.changeRootViewController(with: "listenViewController")

25

स्विफ्ट 2

UIView.transitionWithView(self.window!, duration: 0.5, options: UIViewAnimationOptions.TransitionFlipFromLeft, animations: {
  self.window?.rootViewController = anyViewController
}, completion: nil)

स्विफ्ट 3, 4, 5

UIView.transition(with: self.window!, duration: 0.5, options: UIView.AnimationOptions.transitionFlipFromLeft, animations: {
  self.window?.rootViewController = anyViewController
}, completion: nil)

XCode ने मेरा कोड इस तरह तय किया: `` `UIView.transition (with: self.view.wind_! अवधि: 0.5, विकल्प: UIViewAnimationOptions.transitionFlipFromTop, एनिमेशन: {appDelegate.window .rootViewController = myViewController}, पूरा: nil)। `` `
scaryguy

10

बस यह कोशिश करो। मेरे लिए ठीक काम करता है।

BOOL oldState = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
self.window.rootViewController = viewController;
[UIView transitionWithView:self.window duration:0.5 options:transition animations:^{
    //
} completion:^(BOOL finished) {
    [UIView setAnimationsEnabled:oldState];
}];

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

यह बेहतर है।

- (void)setRootViewController:(UIViewController *)viewController
               withTransition:(UIViewAnimationOptions)transition
                   completion:(void (^)(BOOL finished))completion {
    UIViewController *oldViewController = self.window.rootViewController;
    [UIView transitionFromView:oldViewController.view 
                        toView:viewController.view
                      duration:0.5f
                       options:(UIViewAnimationOptions)(transition|UIViewAnimationOptionAllowAnimatedContent|UIViewAnimationOptionLayoutSubviews)
                    completion:^(BOOL finished) {
        self.window.rootViewController = viewController;
        if (completion) {
            completion(finished);
        }
    }];
}

मैं एक अजीब डिफ़ॉल्ट एनीमेशन था जब बस रूट कुलपति स्विच। पहले संस्करण ने मेरे लिए इससे छुटकारा पा लिया।
जुहान_ ह

दूसरा संस्करण सबव्यू लेआउट को चेतन करेगा, जैसा कि जुहान_ह द्वारा बताया गया है। यदि यह आवश्यक नहीं है, तो या तो हटाने के साथ प्रयोग करें UIViewAnimationOptionAllowAnimatedContent|UIViewAnimationOptionLayoutSubviews, या पहले संस्करण, या किसी अन्य विधि का उपयोग करें।
ftvs

3

आदेश में संक्रमण फ्लिप के साथ समस्या नहीं है बाद में अनुप्रयोग में पुराने दृश्य को भी स्टैक से साफ़ करने के लिए अच्छा है

UIViewController *oldController=self.window.rootViewController;

[UIView transitionWithView:self.window
                  duration:0.5
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{ self.window.rootViewController = nav; }
                completion:^(BOOL finished) {
                    if(oldController!=nil)
                        [oldController.view removeFromSuperview];
                }];

2

सही उत्तर है कि आपको rootViewControllerअपनी खिड़की पर बदलने की आवश्यकता नहीं है । इसके बजाय, एक कस्टम बनाएं UIViewController, इसे एक बार असाइन करें और इसे एक बार में एक चाइल्ड कंट्रोलर प्रदर्शित करें और ज़रूरत पड़ने पर एनीमेशन से बदल दें। आप एक प्रारंभिक बिंदु के रूप में कोड के निम्नलिखित टुकड़े का उपयोग कर सकते हैं:

स्विफ्ट 3.0

import Foundation
import UIKit

/// Displays a single child controller at a time.
/// Replaces the current child controller optionally with animation.
class FrameViewController: UIViewController {

    private(set) var displayedViewController: UIViewController?

    func display(_ viewController: UIViewController, animated: Bool = false) {

        addChildViewController(viewController)

        let oldViewController = displayedViewController

        view.addSubview(viewController.view)
        viewController.view.layoutIfNeeded()

        let finishDisplay: (Bool) -> Void = {
            [weak self] finished in
            if !finished { return }
            oldViewController?.view.removeFromSuperview()
            oldViewController?.removeFromParentViewController()
            viewController.didMove(toParentViewController: self)
        }

        if (animated) {
            viewController.view.alpha = 0
            UIView.animate(
                withDuration: 0.5,
                animations: { viewController.view.alpha = 1; oldViewController?.view.alpha = 0 },
                completion: finishDisplay
            )
        }
        else {
            finishDisplay(true)
        }

        displayedViewController = viewController
    }

    override var preferredStatusBarStyle: UIStatusBarStyle {
        return displayedViewController?.preferredStatusBarStyle ?? .default
    }
}

और जिस तरह से आप इसका उपयोग करते हैं वह है:

...
let rootController = FrameViewController()
rootController.display(UINavigationController(rootViewController: MyController()))
window.rootViewController = rootController
window.makeKeyAndVisible()
...

ऊपर दिए गए उदाहरण से पता चलता है कि आप UINavigationControllerअंदर घोंसला बना सकते हैं FrameViewControllerऔर यह ठीक काम करता है। यह दृष्टिकोण आपको उच्च स्तर का अनुकूलन और नियंत्रण प्रदान करता है। बस FrameViewController.display(_)किसी भी समय कॉल करें आप रूट कंट्रोलर को अपनी विंडो पर बदलना चाहेंगे, और यह आपके लिए वह काम करेगा।


2

यह स्विफ्ट 3 के लिए एक अपडेट है, यह विधि आपके ऐप के प्रतिनिधि में होनी चाहिए, और आप इसे किसी भी दृश्य नियंत्रक से, ऐप प्रतिनिधि के साझा उदाहरण के माध्यम से कहते हैं

func logOutAnimation() {
    let storyBoard = UIStoryboard.init(name: "SignIn", bundle: nil)
    let viewController = storyBoard.instantiateViewController(withIdentifier: "signInVC")
    UIView.transition(with: self.window!, duration: 0.5, options: UIViewAnimationOptions.transitionFlipFromLeft, animations: {
        self.window?.rootViewController = viewController
        self.window?.makeKeyAndVisible()
    }, completion: nil)
}

जो भाग ऊपर विभिन्न प्रश्नों से गायब है, वह है

    self.window?.makeKeyAndVisible()

आशा है कि यह किसी की मदद करता है।


1

AppDelegate.h में:

#define ApplicationDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)]

आपके नियंत्रक में:

[UIView transitionWithView:self.window
                  duration:0.5
                   options:UIViewAnimationOptionTransitionFlipFromLeft
                animations:^{
    ApplicationDelegate.window.rootViewController = newViewController;
    }
                completion:nil];

6
यह स्वीकृत उत्तर के समान है, सिवाय इसके कि स्वरूपण गलत है। क्यों परेशान?
जार्तुरटन

1
यह एक दृश्य या ViewController में आप पर निर्भर नहीं करता है। सबसे बड़ा अंतर यह है कि आप अपने दृश्यों और दर्शकों को पसंद करते हैं कि आप कितने मोटे या पतले हैं।
अधिकतम

0

मैं अपने तरीके का प्रस्ताव करता हूं जो यह मेरी परियोजना में ठीक काम कर रहा है, और यह मुझे अच्छे एनिमेशन प्रदान करता है। मैंने इस पोस्ट में पाए गए अन्य प्रस्तावों का परीक्षण किया है, लेकिन उनमें से कुछ उम्मीद के मुताबिक काम नहीं करते हैं।

- (void)transitionToViewController:(UIViewController *)viewController withTransition:(UIViewAnimationOptions)transition completion:(void (^)(BOOL finished))completion {
// Reset new RootViewController to be sure that it have not presented any controllers
[viewController dismissViewControllerAnimated:NO completion:nil];

[UIView transitionWithView:self.window
                  duration:0.5f
                   options:transition
                animations:^{
                    for (UIView *view in self.window.subviews) {
                        [view removeFromSuperview];
                    }
                    [self.window addSubview:viewController.view];

                    self.window.rootViewController = viewController;
                } completion:completion];
}

0

अच्छा मीठा एनीमेशन (स्विफ्ट 4.x के साथ परीक्षण):

extension AppDelegate {
   public func present(viewController: UIViewController) {
        guard let window = window else { return }
        UIView.transition(with: window, duration: 0.5, options: .transitionFlipFromLeft, animations: {
            window.rootViewController = viewController
        }, completion: nil)
    }
}

के साथ बुलाना

guard let delegate = UIApplication.shared.delegate as? AppDelegate else { return }
delegate.present(viewController: UIViewController())
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.