iPhone - 关闭多个ViewControllers

Osc*_*eli 45 iphone uiviewcontroller dismiss

我有一个很长的View Controllers层次结构;

在第一个View Controller中我使用此代码:

SecondViewController *svc = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
[self presentModalViewController:svc animated:YES];    
[svc release];
Run Code Online (Sandbox Code Playgroud)

在第二个View Controller中,我使用以下代码:

ThirdViewController *tvc = [[ThirdViewController alloc] initWithNibName:@"ThirdViewController" bundle:nil];
[self presentModalViewController:tvc animated:YES];    
[tvc release];
Run Code Online (Sandbox Code Playgroud)

等等.

所以有一段时间我有很多View Controllers,我需要回到第一个View Controller.如果我一次回来一步,我会在每个View Controller中使用这段代码:

[self dismissModalViewControllerAnimated:YES];
Run Code Online (Sandbox Code Playgroud)

如果我想直接从第六个View Controller返回到第一个,我必须做什么才能立即解除所有控制器?

谢谢

Suz*_*Suz 64

是.已经有很多答案,但我只是想在列表的末尾添加一个答案.问题是我们需要在层次结构的基础上获得对视图控制器的引用.和@Juan Munhoes Junior的回答一样,你可以走层次结构,但是用户可能会采用不同的路线,所以这是一个非常脆弱的答案.扩展这个简单的解决方案并不难,只需简单地遍历层次结构寻找堆栈的底部.在底部调用解雇也将获得所有其他人.

-(void)dismissModalStack {
    UIViewController *vc = self.presentingViewController;
    while (vc.presentingViewController) {
        vc = vc.presentingViewController;
    }
    [vc dismissViewControllerAnimated:YES completion:NULL];
}
Run Code Online (Sandbox Code Playgroud)

这很简单灵活:如果要在堆栈中查找特定类型的视图控制器,可以添加基于的逻辑[vc isKindOfClass:[DesiredViewControllerClass class]].


Osc*_*eli 24

我找到了解决方案.

当然你可以在最明显的地方找到解决方案,所以从UIViewController参考中读取dismissModalViewControllerAnimated方法......

如果连续呈现多个模态视图控制器,从而构建一组模态视图控制器,则在堆栈中较低的视图控制器上调用此方法会解除其直接子视图控制器和堆栈上该子级上方的所有视图控制器.发生这种情况时,只有最顶层的视图以动画方式被删除; 任何中间视图控制器都可以从堆栈中删除.最顶层的视图使用其模态过渡样式被忽略,这可能与堆栈中较低的其他视图控制器使用的样式不同.

所以它足以在目标视图上调用dismissModalViewControllerAnimated.我使用了以下代码:

[[[[[self parentViewController] parentViewController] parentViewController] parentViewController] dismissModalViewControllerAnimated:YES];
Run Code Online (Sandbox Code Playgroud)

回到我家.

  • 注意:在iOS5中,这改为"presentsViewController":http://game4mob.com/index.php/jawbreaker/66-dismiss-modal-view-in-ios5-sdk (11认同)
  • 警告:我现在你并不确切地知道你必须弹出多少视图,它不能正常工作. (2认同)

Jak*_*lář 15

用于全屏解雇的iOS 8+通用方法,没有错误的动画上下文.在Objective-C和Swift中

Objective-C的

- (void)dismissModalStackAnimated:(bool)animated completion:(void (^)(void))completion {
    UIView *fullscreenSnapshot = [[UIApplication sharedApplication].delegate.window snapshotViewAfterScreenUpdates:false];
    [self.presentedViewController.view insertSubview:fullscreenSnapshot atIndex:NSIntegerMax];
    [self dismissViewControllerAnimated:animated completion:completion];
}
Run Code Online (Sandbox Code Playgroud)

迅速

func dismissModalStack(animated: Bool, completion: (() -> Void)?) {
    if let fullscreenSnapshot = UIApplication.shared.delegate?.window??.snapshotView(afterScreenUpdates: false) {
        presentedViewController?.view.addSubview(fullscreenSnapshot)
    }
    if !isBeingDismissed {
        dismiss(animated: animated, completion: completion)
    }
}
Run Code Online (Sandbox Code Playgroud)

TL;博士

其他解决方案有什么问题?

有许多解决方案,但没有一个计算错误的解雇上下文所以:

根- >礼物乙- >介绍ç,你想解雇从C的A,你可以officialy通过调用dismissViewControllerAnimatedrootViewController.

 [[UIApplication sharedApplication].delegate.window.rootViewController dismissModalStackAnimated:true completion:nil];
Run Code Online (Sandbox Code Playgroud)

但是,从C调用此根的调用将导致错误转换的正确行为(B到A将被看到而不是C到A).


所以

我创建了普遍的解雇方法.此方法将获取当前全屏快照并将其放在接收器的呈现视图控制器上,然后将其全部关闭. (示例:从C调用默认解雇,但B实际上被视为解雇)

  • 没错,addSubview 是实现相同结果的更简单、更短的方法 (2认同)

Tho*_*eek 14

假设您的第一个视图控制器也是根/初始视图控制器(您在Storyboard中指定为初始视图控制器的控制器).您可以将其设置为侦听请求以关闭其所有呈现的视图控制器:

在FirstViewController中:

- (void)viewDidLoad {
    [super viewDidLoad];

    // listen to any requests to dismiss all stacked view controllers
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissAllViewControllers:) name:@"YourDismissAllViewControllersIdentifier" object:nil];

    // the remainder of viewDidLoad ...
}

// this method gets called whenever a notification is posted to dismiss all view controllers
- (void)dismissAllViewControllers:(NSNotification *)notification {
    // dismiss all view controllers in the navigation stack
    [self dismissViewControllerAnimated:YES completion:^{}];
}
Run Code Online (Sandbox Code Playgroud)

在导航堆栈中的任何其他视图控制器中,决定我们应该返回到导航堆栈的顶部:

[[NSNotificationCenter defaultCenter] postNotificationName:@"YourDismissAllViewControllersIdentifier" object:self];
Run Code Online (Sandbox Code Playgroud)

这应该使用动画解除所有模态呈现的视图控制器,只留下根视图控制器.如果您的初始视图控制器是UINavigationController并且第一个视图控制器设置为其根视图控制器,这也适用.

额外提示:通知名称相同非常重要.将应用程序中的某个通知名称定义为变量可能是一个好主意,因为不会因输入错误而导致错误通知.


Har*_*ris 6

大多数解决方案的问题是,当您关闭呈现的 viewController 堆栈时,用户将在堆栈中短暂地看到第一个呈现的 viewController,因为它正在被关闭。Jakub 的出色解决方案解决了这个问题。这是基于他的回答的扩展。

extension UIViewController {

    func dismissAll(animated: Bool, completion: (() -> Void)? = nil) {
        if let optionalWindow = UIApplication.shared.delegate?.window, let window = optionalWindow, let rootViewController = window.rootViewController, let presentedViewController = rootViewController.presentedViewController  {
            if let snapshotView = window.snapshotView(afterScreenUpdates: false) {
                presentedViewController.view.addSubview(snapshotView)
                presentedViewController.modalTransitionStyle = .coverVertical
            }
            if !isBeingDismissed {
                rootViewController.dismiss(animated: animated, completion: completion)
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

用法:从任何呈现的 viewController 中调用此扩展函数,您希望将其解散回根目录。

@IBAction func close() {
    dismissAll(animated: true)
}
Run Code Online (Sandbox Code Playgroud)


Jua*_*ior 5

[[self presentingViewController]presentingViewController]dismissModalViewControllerAnimated:NO];
Run Code Online (Sandbox Code Playgroud)

您还可以在要关闭的所有控制器中实现委托