iPhone-关闭多个ViewController

iPhone-关闭多个ViewController,iphone,uiviewcontroller,dismiss,Iphone,Uiviewcontroller,Dismiss,我有一个长远的观点 在第一个视图控制器中,我使用以下代码: SecondViewController *svc = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil]; [self presentModalViewController:svc animated:YES]; [svc release]; 在第二个视图控制器中,我使用以下代码: ThirdViewControll

我有一个长远的观点

在第一个视图控制器中,我使用以下代码:

SecondViewController *svc = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
[self presentModalViewController:svc animated:YES];    
[svc release];
在第二个视图控制器中,我使用以下代码:

ThirdViewController *tvc = [[ThirdViewController alloc] initWithNibName:@"ThirdViewController" bundle:nil];
[self presentModalViewController:tvc animated:YES];    
[tvc release];
[self dismissModalViewControllerAnimated:YES];
等等

所以有一段时间我有很多视图控制器,我需要回到第一个视图控制器。 如果我一次返回一个步骤,我会在每个视图控制器中使用以下代码:

ThirdViewController *tvc = [[ThirdViewController alloc] initWithNibName:@"ThirdViewController" bundle:nil];
[self presentModalViewController:tvc animated:YES];    
[tvc release];
[self dismissModalViewControllerAnimated:YES];
如果我想直接从第六个视图控制器返回到第一个视图控制器,我需要做什么来一次关闭所有控制器


谢谢

关闭最热门的VC动画,其他的则不用。如果你有三个模态VC

[self dismissModalViewControllerAnimated:NO]; // First
[self dismissModalViewControllerAnimated:NO]; // Second
[self dismissModalViewControllerAnimated:YES]; // Third
编辑:如果您只想用一种方法执行此操作,请将层次结构保存到VC数组中,并取消最后一个已设置动画的对象和其他未设置动画的对象。

我找到了解决方案

当然,您可以在最明显的地方找到解决方案,因此从UIViewController参考中读取DismissModalViewController激活方法

如果您呈现多个模态视图 控制器相继出现,因此 构建一个模态视图堆栈 控制器上调用此方法 查看堆栈中较低的控制器 取消其直接子视图 控制器和所有视图控制器 在堆栈上的子对象上方。什么时候 这种情况发生时,只有最上面的视图 以一种生动的方式被抛弃; 任何中间视图控制器都是可用的 只是从堆栈中删除。这个 使用其 模态转换样式,可能 不同于其他人使用的样式 查看堆栈中较低的控制器

因此,在目标视图上调用dismissModalViewControllerAnimated就足够了。 我使用了以下代码:

[[[[[self parentViewController] parentViewController] parentViewController] parentViewController] dismissModalViewControllerAnimated:YES];

回到我家。

首先,奥斯卡·佩利感谢你的代码

要在开始时启动navigationController,可以通过这种方式使其更具动态性。(如果您不知道堆栈中ViewController的数量)


如果你要回到起点,你可以使用代码 [self.navigationController-popToRootViewControllerAnimated:是]

试试这个

ThirdViewController *tvc = [[ThirdViewController alloc] initWithNibName:@"ThirdViewController" bundle:nil];
[self.view addsubview:tvc];    
[tvc release];

您还可以在所有要解除的控制器中实现委托,例如您的第一个视图控制器也是根/初始视图控制器(您在故事板中指定为初始视图控制器的控制器)。您可以将其设置为侦听请求以关闭所有显示的视图控制器:

在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:^{}];
}
+ (UIViewController*)topmostViewController
{
    UIViewController* vc = [[[UIApplication sharedApplication] keyWindow] rootViewController];
    while(vc.presentedViewController) {
        vc = vc.presentedViewController;
    }
    return vc;
}

+ (void)returnToRootViewController
{
    UIViewController* vc = [UIViewController topmostViewController];
    while (vc) {
        if([vc isKindOfClass:[UINavigationController class]]) {
            [(UINavigationController*)vc popToRootViewControllerAnimated:NO];
        }
        if(vc.presentingViewController) {
            [vc dismissViewControllerAnimated:NO completion:^{}];
        }
        vc = vc.presentingViewController;
    }
}
在导航堆栈下的任何其他视图控制器中,决定我们应该返回到导航堆栈的顶部:

[[NSNotificationCenter defaultCenter] postNotificationName:@"YourDismissAllViewControllersIdentifier" object:self];
这将关闭所有以动画方式显示的视图控制器,只留下根视图控制器。如果初始视图控制器是UINavigationController,并且第一个视图控制器设置为其根视图控制器,则此操作也有效


额外提示:通知名称必须相同,这一点很重要。在应用程序中的某个地方将此通知名称定义为变量可能是一个好主意,这样就不会因为键入错误而导致通信错误。

如果您使用的是all are模型视图控制器,则可以使用通知来取消所有预设的视图控制器

  id vc = [self presentingViewController];
  id lastVC = self;
  while (vc != nil) {
    id tmp = vc;
    vc = [vc presentingViewController];
    lastVC = tmp;
  }
  [lastVC dismissViewControllerAnimated:YES completion:^{
}];
1.像这样在RootViewController中注册通知

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(dismissModelViewController)
                                             name:dismissModelViewController
                                           object:nil];
2.在rootviewController中实现dismissModelViewController函数

- (void)dismissModelViewController
{
    While (![self.navigationController.visibleViewController isMemberOfClass:[RootviewController class]])
    {
        [self.navigationController.visibleViewController dismissViewControllerAnimated:NO completion:nil];
    }
}
3.每次关闭或关闭按钮事件都会发布通知

   [[NSNotificationCenter defaultCenter] postNotificationName:dismissModelViewController object:self];

使用此通用解决方案解决此问题:

- (UIViewController*)topViewController
{
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
    while (topController.presentedViewController) {
        topController = topController.presentedViewController;
    }
    return topController;
}


- (void)dismissAllModalController{

    __block UIViewController *topController = [self topViewController];

    while (topController.presentingViewController) {
        [topController dismissViewControllerAnimated:NO completion:^{

        }];
        topController = [self topViewController];
    }
}

下面是一个解决方案,我使用它弹出并关闭所有视图控制器,以便返回到根视图控制器。我在UIViewController的一个类别中有这两种方法:

- (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:^{}];
}
+ (UIViewController*)topmostViewController
{
    UIViewController* vc = [[[UIApplication sharedApplication] keyWindow] rootViewController];
    while(vc.presentedViewController) {
        vc = vc.presentedViewController;
    }
    return vc;
}

+ (void)returnToRootViewController
{
    UIViewController* vc = [UIViewController topmostViewController];
    while (vc) {
        if([vc isKindOfClass:[UINavigationController class]]) {
            [(UINavigationController*)vc popToRootViewControllerAnimated:NO];
        }
        if(vc.presentingViewController) {
            [vc dismissViewControllerAnimated:NO completion:^{}];
        }
        vc = vc.presentingViewController;
    }
}
那我就打电话

[UIViewController returnToRootViewController];

对。已经有很多答案了,但我还是要在列表的末尾加上一个。问题是我们需要在层次结构的基础上获取对视图控制器的引用。正如@Juan Munhoes Junior的回答一样,你可以在层次结构中穿行,但用户可能会选择不同的路线,因此这是一个非常脆弱的回答。扩展这个简单的解决方案并不困难,但是只需在层次结构中查找堆栈的底部即可。在最下面的一个打电话解雇也会得到所有其他人

-(void)dismissModalStack {
    UIViewController *vc = self.presentingViewController;
    while (vc.presentingViewController) {
        vc = vc.presentingViewController;
    }
    [vc dismissViewControllerAnimated:YES completion:NULL];
}
这既简单又灵活:如果希望在堆栈中查找特定类型的视图控制器,可以添加基于
[vc isKindOfClass:[DesiredViewControllerClass]]
的逻辑

在Swift中:

self.presentingViewController?.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)

swift版本,根据评论添加了一些内容


简单递归闭合器:

extension UIViewController {
    final public func dismissEntireStackAndSelf(animate: Bool = true) {
        // Always false on non-calling controller
        presentedViewController?.ip_dismissEntireStackAndSelf(false)
        self.dismissViewControllerAnimated(animate, completion: nil)
    }
}
这将强制关闭每个子控制器,然后仅设置自身动画。你可以随意切换,但是如果你设置每个控制器的动画,它们会一个接一个的移动,速度会很慢

召唤

iOS 8+用于全屏解雇的通用方法,无错误的动画上下文。在Objective-C和Swift中 目标-C 敏捷的
tl;博士 其他解决方案有什么问题?

有许多解决方案,但没有一个与错误的驳回上下文相关,因此:

e、 g.根A->Presents B->Presents C如果您想从C解除到A,您可以通过调用
rootViewController
上的
dismissViewControllerAnimated
来正式解除

 [[UIApplication sharedApplication].delegate.window.rootViewController dismissModalStackAnimated:true completion:nil];
但是从C调用此根将导致正确的行为和错误的转换(将看到B到A,而不是C到A)


so


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

基于上述答案的Swift扩展:

extension UIViewController {

    func dismissUntilAnimated<T: UIViewController>(animated: Bool, viewController: T.Type, completion: ((viewController: T) -> Void)?) {
        var vc = presentingViewController!
        while let new = vc.presentingViewController where !(new is T) {
            vc = new
        }
        vc.dismissViewControllerAnimated(animated, completion: {
            completion?(viewController: vc as! T)
        })
    }
}
扩展UIViewController{ func DismissionTilanimated(动画:Bool,viewController:T.类型,完成:((viewController:T)->Void)?){ var vc=当前视图控制器!
 [[UIApplication sharedApplication].delegate.window.rootViewController dismissModalStackAnimated:true completion:nil];
extension UIViewController {

    func dismissUntilAnimated<T: UIViewController>(animated: Bool, viewController: T.Type, completion: ((viewController: T) -> Void)?) {
        var vc = presentingViewController!
        while let new = vc.presentingViewController where !(new is T) {
            vc = new
        }
        vc.dismissViewControllerAnimated(animated, completion: {
            completion?(viewController: vc as! T)
        })
    }
}
extension UIViewController {

    /// Dismiss all modally presented view controllers until a specified view controller is reached. If no view controller is found, this function will do nothing.

    /// - Parameter reached:      The type of the view controller to dismiss until.
    /// - Parameter flag:         Pass `true` to animate the transition.
    /// - Parameter completion:   The block to execute after the view controller is dismissed. This block contains the instance of the `presentingViewController`. You may specify `nil` for this parameter.
    func dismiss<T: UIViewController>(until reached: T.Type, animated flag: Bool, completion: ((T) -> Void)? = nil) {
        guard let presenting = presentingViewController as? T else {
            return presentingViewController?.dismiss(until: reached, animated: flag, completion: completion) ?? ()
        }

        presenting.dismiss(animated: flag) {
            completion?(presenting)
        }
    }
}
any intermediate view controllers are simply removed from the stack.
Root -> A -> B -> C -> D ... -> Z
extension UIViewController {

    func dismissModalStack(animated: Bool, completion: (() -> Void)?) {
        let fullscreenSnapshot = UIApplication.shared.delegate?.window??.snapshotView(afterScreenUpdates: false)
        if !isBeingDismissed {
            var rootVc = presentingViewController
            while rootVc?.presentingViewController != nil {
                rootVc = rootVc?.presentingViewController
            }
            let secondToLastVc = rootVc?.presentedViewController
            if fullscreenSnapshot != nil {
                secondToLastVc?.view.addSubview(fullscreenSnapshot!)
            }
            secondToLastVc?.dismiss(animated: false, completion: {
                rootVc?.dismiss(animated: true, completion: completion)
            })
        }
    }
}
self.view.window!.rootViewController?.dismissViewControllerAnimated(false, completion: nil)
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)
            }
        }
    }

}
@IBAction func close() {
    dismissAll(animated: true)
}
var vc : UIViewController = self.presentingViewController!
        while ((vc.presentingViewController) != nil) {
            vc = vc.presentingViewController!
        }
        vc.dismiss(animated: true, completion: nil)