RootViewControll Switch Transition Animation


125

Có cách nào để có hiệu ứng Chuyển tiếp / hoạt hình trong khi thay thế một trình điều khiển chế độ xem hiện tại làm trình điều khiển rootview bằng một trình điều khiển mới trong appDelegate không?

Câu trả lời:


272

Bạn có thể gói chuyển đổi rootViewControllertrong khối hoạt hình chuyển tiếp:

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

5
Này Ole, tôi đã thử cách tiếp cận này, nó hoạt động một phần, ứng dụng của tôi chỉ ở chế độ ngang, nhưng bằng cách thực hiện chuyển đổi rootview điều khiển, trình điều khiển chế độ xem mới được trình bày ở chế độ dọc và bắt đầu nhanh chóng chuyển sang chế độ ngang , làm thế nào để giải quyết điều đó?
Chris Chen

4
Tôi đã trả lời câu hỏi của Chris Chen (hy vọng! Có thể?) Trong câu hỏi riêng của anh ấy ở đây: stackoverflow.com/questions/8053832/iêu
Kalle

1
hey tôi muốn một sự chuyển đổi đẩy trong cùng một hình ảnh động tôi có thể đạt được điều đó?
Người dùng 1531343

14
Tôi đã nhận thấy một số vấn đề với điều này, cụ thể là các phần tử bị đặt sai chỗ / các phần tử được tải một cách lười biếng. Ví dụ: nếu bạn không có thanh điều hướng trên vc gốc hiện có, thì hãy tạo hiệu ứng cho một vc mới có một, hoạt ảnh hoàn thành VÀ THÌ thanh điều hướng được thêm vào. Nó trông có vẻ ngớ ngẩn - bất kỳ suy nghĩ về lý do tại sao điều này có thể, và những gì có thể được thực hiện?
anon_dev1234

1
Tôi đã thấy rằng việc gọi newViewController.view.layoutIfNeeded()trước khi khối hoạt hình khắc phục sự cố với các phần tử được tải nhanh.
Whoa

66

Tôi tìm thấy điều này và hoạt động hoàn hảo:

trong ứng dụng của bạnDegegate:

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

trong ứng dụng của bạn

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

tín dụng:

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


Điều này có hỗ trợ màn hình tự động xoay?
Wingzero

1
Giải pháp này hoạt động tốt hơn trong trường hợp của tôi. Khi sử dụng quá trình chuyển đổiWithView, bộ điều khiển xem gốc mới được đặt đúng cho đến khi quá trình chuyển đổi hoàn thành. Cách tiếp cận này cho phép bộ điều khiển xem gốc mới được thêm vào cửa sổ, được đặt ra và sau đó được chuyển đổi.
Fostah

@Wingzero trễ một chút, nhưng, điều này sẽ cho phép bất kỳ loại chuyển đổi nào, thông qua UIView.animations (giả sử, một CGAffineTransform với xoay) hoặc CAAnimation tùy chỉnh.
Có thể

41

Tôi đang đăng câu trả lời của Chúa Giêsu được thực hiện trong nhanh chóng. Nó lấy định danh của trình điều khiển khung nhìn làm đối số, tải từ bảng phân cảnh mong muốn và thay đổi rootViewContaptor bằng hình ảnh động.

Cập nhật Swift 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();
    });
  }

Cập nhật Swift 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;
  }

Sau đó, bạn có một cách sử dụng rất đơn giản từ mọi nơi:

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

Cập nhật Swift 3.0

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

25

Swift 2

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

Swift 3, 4, 5

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

XCode đã sửa mã của tôi như thế này: `` `UIView.transition (với: self.view.window!, Thời gian: 0,5, tùy chọn: UIViewAnimationOptions.transitionFlipFromTop, hình động: {appDelegate.window? .RootView `` `
đáng sợ

10

hãy thử cái này Hoạt động tốt cho tôi.

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

BIÊN TẬP:

Cái này thì tốt hơn.

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

Tôi đã có một hình ảnh động mặc định kỳ lạ khi chỉ cần chuyển đổi root VC. Phiên bản đầu tiên đã loại bỏ điều đó cho tôi.
juhan_h ngày

Phiên bản thứ hai sẽ làm sinh động bố cục của khung nhìn phụ, như được đề cập bởi juhan_h. Nếu điều này là không bắt buộc, hãy thử nghiệm loại bỏ UIViewAnimationOptionAllowAnimatedContent|UIViewAnimationOptionLayoutSubviewshoặc sử dụng phiên bản đầu tiên hoặc một số phương pháp khác.
ftvs

3

Để không gặp vấn đề với quá trình chuyển đổi, hãy lật lại trong ứng dụng, thật tốt để xóa chế độ xem cũ khỏi ngăn xếp.

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

Câu trả lời đúng là bạn không cần thay thế rootViewControllertrên cửa sổ của mình. Thay vào đó, hãy tạo một tùy chỉnh UIViewController, gán nó một lần và để nó hiển thị một bộ điều khiển con tại một thời điểm và thay thế nó bằng hình ảnh động nếu cần. Bạn có thể sử dụng đoạn mã sau đây làm điểm bắt đầu:

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

Và cách bạn sử dụng là:

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

Ví dụ trên chứng tỏ rằng bạn có thể lồng UINavigationControllerbên trong FrameViewControllervà nó hoạt động tốt. Cách tiếp cận này cung cấp cho bạn mức độ tùy biến và kiểm soát cao. Chỉ cần gọi FrameViewController.display(_)bất cứ lúc nào bạn muốn thay thế bộ điều khiển gốc trên cửa sổ của bạn và nó sẽ thực hiện công việc đó cho bạn.


2

Đây là bản cập nhật cho swift 3, phương thức này phải có trong đại biểu ứng dụng của bạn và bạn gọi nó từ bất kỳ trình điều khiển xem nào, thông qua một phiên bản chia sẻ của đại biểu ứng dụng

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

Phần còn thiếu trong các câu hỏi khác nhau ở trên, là

    self.window?.makeKeyAndVisible()

Hy vọng điều này sẽ giúp được ai đó.


1

trong AppDelegate.h:

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

trong Bộ điều khiển của bạn:

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

6
Điều này giống như câu trả lời được chấp nhận, ngoại trừ định dạng sai. Quan tâm làm gì?
jrturton

1
Điều này không phụ thuộc vào bạn đang ở trong View hay ViewContoder. Sự khác biệt lớn nhất mang tính triết học nhiều hơn về độ dày hay mỏng mà bạn thích Lượt xem và ViewControllers của bạn.
Tối đa

0

Tôi đề xuất theo cách của tôi mà nó đang hoạt động tốt trong dự án của tôi, và nó cung cấp cho tôi hình ảnh động tốt. Tôi đã thử nghiệm các đề xuất khác được tìm thấy trong bài viết này, nhưng một số trong số chúng không hoạt động như mong đợi.

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

Hoạt hình đẹp ngọt ngào (đã thử nghiệm với Swift 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)
    }
}

Gọi với

guard let delegate = UIApplication.shared.delegate as? AppDelegate else { return }
delegate.present(viewController: UIViewController())
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.