답변:
rootViewController
전환 애니메이션 블록에서 전환을 래핑 할 수 있습니다 .
[UIView transitionWithView:self.window
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{ self.window.rootViewController = newViewController; }
completion:nil];
newViewController.view.layoutIfNeeded()
애니메이션 블록 전에 호출 하면 느리게로드 된 요소의 문제가 해결됩니다.
나는 이것을 발견하고 완벽하게 작동합니다.
앱에서
- (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];
크레딧 :
나는 예수의 답변을 신속하게 이행하고 있습니다. 뷰 컨트롤러의 식별자를 인수로 가져와 스토리 보드에서 원하는 뷰 컨트롤러에서로드하고 애니메이션으로 rootViewController를 변경합니다.
스위프트 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")
스위프트 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)
이것을 시도하십시오. 나를 위해 잘 작동합니다.
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
하거나 첫 번째 버전을 사용하거나 다른 방법을 사용하십시오.
앱에서 나중에 전환 플립에 문제가 발생하지 않도록 스택에서 이전보기를 지우는 것이 좋습니다.
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];
}];
정답은 rootViewController
창에서 를 교체 할 필요가 없다는 것 입니다. 대신 custom을 만들고 한 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(_)
창에서 루트 컨트롤러를 교체하고 싶을 때 언제든지 전화 하면 해당 작업이 자동으로 수행됩니다.
이것은 신속한 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()
이것이 누군가를 돕기를 바랍니다.
AppDelegate.h에서 :
#define ApplicationDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)]
컨트롤러에서 :
[UIView transitionWithView:self.window
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
ApplicationDelegate.window.rootViewController = newViewController;
}
completion:nil];
내 프로젝트에서 잘 작동하는 방식을 제안하고 좋은 애니메이션을 제공합니다. 이 게시물에있는 다른 제안을 테스트했지만 그중 일부가 예상대로 작동하지 않습니다.
- (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];
}
멋진 달콤한 애니메이션 (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)
}
}
와 전화
guard let delegate = UIApplication.shared.delegate as? AppDelegate else { return }
delegate.present(viewController: UIViewController())