RootViewController Anahtar Geçiş Animasyonu


126

Rootviewcontroller olarak mevcut bir viewcontroller'ı appDelegate'te yenisiyle değiştirirken bir Geçiş / animasyon efektine sahip olmanın bir yolu var mı?

Yanıtlar:


273

Anahtarını rootViewControllerbir geçiş animasyon bloğunda kaydırabilirsiniz :

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

5
hey Ole, bu yaklaşımı denedim, kısmen çalıştı, uygulamam sadece yatay modda kalacak, ancak rootview kontrolör geçişi yaparak, yeni sunulan görünüm kontrolörü başlangıçta dikey olarak yüklenir ve hızla yatay moda döndürülür , bunu nasıl çözebilirim?
Chris Chen

4
Chris Chen'in sorusunu (umarım! Belki?) Ayrı sorusuyla yanıtladım: stackoverflow.com/questions/8053832/…
Kalle

1
hey aynı animasyonda bir push geçişi istiyorum bunu başarabilir miyim?
Kullanıcı 1531343

14
Bununla ilgili bazı sorunlar, yani yanlış yerleştirilmiş öğeler / tembel yüklü öğeler fark ettim. Örneğin, mevcut kök vc'de bir gezinme çubuğunuz yoksa, yeni bir vc'ye animasyon uygulayın, animasyon tamamlanır VE SONRA gezinme çubuğu eklenir. Biraz saçma görünüyor - bunun neden olabileceği ve ne yapılabileceği hakkında herhangi bir fikriniz var mı?
anon_dev1234

1
newViewController.view.layoutIfNeeded()Animasyon bloğundan önce aramanın , tembel yüklü öğelerle ilgili sorunları çözdüğünü buldum .
Vay

66

Bunu buldum ve mükemmel çalışıyor:

uygulamanızdaDelegate:

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

uygulamanızda

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

kredi:

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


Bu otomatik ekran döndürmeyi destekliyor mu?
Wingzero

1
Bu çözüm benim durumumda daha iyi çalıştı. TransitionWithView kullanılırken, yeni kök görünüm denetleyicisi, geçiş tamamlanana kadar düzgün bir şekilde yerleştirildi. Bu yaklaşım, yeni kök görünüm denetleyicisinin pencereye eklenmesine, düzenlenmesine ve ardından geçişine izin verir.
Fostah

@Wingzero biraz geç, ancak bu, UIView.animations (örneğin, döndürmeli bir CGAffineTransform) veya özel bir CAAnimation aracılığıyla her türlü geçişe izin verir.
Can

41

Hızlı bir şekilde uygulanan İsa cevabını gönderiyorum. Viewcontroller'ın tanımlayıcısını bir argüman olarak alır, film şeridinden istenenViewController'ı yükler ve rootViewController'ı animasyonla değiştirir.

Swift 3.0 Güncellemesi:

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

Swift 2.2 Güncellemesi:

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

Ardından, her yerden çok basit bir kullanımınız olur:

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

Swift 3.0 güncellemesi

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

26

Swift 2

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

Hızlı 3, 4, 5

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

XCode kodumu şu şekilde düzeltti: `` `` UIView.transition (with: self.view.window !, süre: 0.5, seçenekler: UIViewAnimationOptions.transitionFlipFromTop, animasyonlar: {appDelegate.window? .RootViewController = myViewController}, tamamlama: nil) ``
scaryguy

10

sadece bunu dene. Benim için iyi çalışıyor.

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

DÜZENLE:

Bu daha iyi.

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

Sadece kök VC'yi değiştirirken garip bir varsayılan animasyonum vardı. İlk versiyon benim için bundan kurtuldu.
juhan_h

Juhan_h'de belirtildiği gibi, ikinci sürüm alt görünüm düzenini canlandıracaktır. Bu gerekli değilse, kaldırmayı deneyin UIViewAnimationOptionAllowAnimatedContent|UIViewAnimationOptionLayoutSubviewsveya ilk sürümü veya başka bir yöntemi kullanın.
ftvs

3

Geçişle ilgili sorun yaşamamak için daha sonra uygulamada çevirin, eski görünümü yığından da temizlemek iyidir

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

Doğru cevap, rootViewControllerpencerenizin üzerini değiştirmenize gerek olmadığıdır . Bunun yerine, özel birUIViewController kez atayın ve her seferinde bir alt denetleyici görüntülemesine izin verin ve gerekirse animasyonla değiştirin. Aşağıdaki kod parçasını başlangıç ​​noktası olarak kullanabilirsiniz:

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

Ve onu kullanma şekliniz:

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

Yukarıdaki örnek, UINavigationControlleriçine yuva yapabileceğinizi FrameViewControllerve bunun iyi çalıştığını göstermektedir. Bu yaklaşım size yüksek düzeyde özelleştirme ve kontrol sağlar. FrameViewController.display(_)Pencerenizdeki kök denetleyiciyi değiştirmek istediğiniz herhangi bir zamanda arayın , o işi sizin için yapacaktır.


2

Bu, Swift 3 için bir güncellemedir, bu yöntem uygulama temsilcinizde olmalıdır ve uygulama temsilcisinin paylaşılan bir örneği aracılığıyla herhangi bir görünüm denetleyicisinden çağırırsınız.

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

Yukarıdaki çeşitli sorularda eksik olan kısım şudur:

    self.window?.makeKeyAndVisible()

Umarım bu birine yardımcı olur.


1

AppDelegate.h'de:

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

Denetleyicinizde:

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

6
Bu, biçimlendirmenin yanlış olması dışında, kabul edilen cevapla aynıdır. Neden uğraşıyorsun?
jrturton

1
Bu, bir View veya ViewController'da olmanıza bağlı değildir. En büyük fark, Views ve ViewControllers'ınızın ne kadar kalın veya ince olmasını istediğiniz konusunda daha felsefi.
Maksimum

0

Projemde iyi giden yolumu öneriyorum ve bana iyi animasyonlar sunuyor. Bu yazıda bulunan diğer önerileri test ettim, ancak bazıları beklendiği gibi çalışmıyor.

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

Güzel tatlı animasyon (Swift 4.x ile test edildi):

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

İle ara

guard let delegate = UIApplication.shared.delegate as? AppDelegate else { return }
delegate.present(viewController: UIViewController())
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.