关闭两个模态视图控制器

6
我发现有几个关于这个问题的问题,但是答案没有解决我的问题。
我有两个控制器,我使用presentModalViewController呈现它们。
我为被Main Controller调用的第一个控制器添加了modalTransitionStyle。第一个控制器正常地呈现了第二个控制器(没有转换样式)。
FirstVC *first = [[FirstVC alloc] initWithNibName:@"FirstVC" bundle:nil];
first.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentModalViewController:first animated:YES];

SecondVC *second = [[SecondVC alloc] initWithNibName:@"SecondVC" bundle:nil];
[self presentModalViewController:second animated:YES];

以下是我用来转到MainVC的代码:

[self.presentingViewController.presentingViewController dismissModalViewControllerAnimated:YES];

这就是发生的事情:
页面没有展开。我遇到这个问题的原因是什么?
6个回答

6
在我的实验中,似乎在部分翻页后不能同时拥有标准的展示(垂直封面)并将它们同时消除,除非你使用无动画设置来完成消除。
然而,解决这个问题的方法是以无动画方式消除secondVC(这段代码位于secondVC中)。
-(IBAction)dismissSelf:(id)sender {
    [self dismissViewControllerAnimated:NO completion:nil];
}

然后在第一个VC中,再次使用动画在viewDidAppear中dismiss,测试控制器是否正在显示:

-(void)viewDidAppear:(BOOL)animated {
    if (![self isBeingPresented]) {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

尽管上述代码可以使返回到初始控制器的视图,但在卷曲效果未消失之前,您会看到firstVC的视图。如果您不想看到这个问题,那么我找到的唯一解决方法是,在关闭secondVC之前,创建secondVC的图像,并将其作为(在图像视图中)添加到firstVC的子视图中。因此,要实现这一点,secondVC中的代码应该改为以下内容(请注意,您必须链接到QuartzCore并将其导入secondVC才能使此方法生效):

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    UIImage *img = [self imageWithView:self.view];
    FirstViewController *first = (FirstViewController *)self.presentingViewController;
    UIImageView *iv = [[UIImageView alloc] initWithFrame:first.view.bounds];
    iv.image = img;
    [first.view addSubview:iv];
}


-(IBAction)dismissSelf:(id)sender {
    [self dismissViewControllerAnimated:NO completion:nil];
}


- (UIImage *)imageWithView:(UIView *)view {
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, [[UIScreen mainScreen] scale]);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;
}

我已经成功地通过使用[self.presentingViewController dismissViewControllerAnimated:NO completion:^{[[NSNotificationCenter defaultCenter] postNotificationName:@"BACKTOMAIN" object:nil];}];解决了这个问题。然后在接收控制器中,我添加了[self dismissModalViewControllerAnimated:YES];。谢谢你的回答 :) - Lie-An

3

您需要使用以下调用来依次展示两个观点:

[self presentViewController:firstViewController animated:YES completion:^(
    [self presentViewController:secondViewController animated:YES completion:^(

    }];
}];

这样操作应该更加流畅。另外,要知道在此之后您将不得不将这两个viewControllers移除。

[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{
    [self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{

    }];
}];

谢谢你的回答。但是第二个视图控制器只有在点击第一个控制器视图中的一个按钮后才会被调用。 - Lie-An
啊,那就确保在结束后将它们都拿掉。 - HalR
你好,HalR。你的回答对我很有帮助。我的做法是在完成块内发布通知。code[self.presentingViewController dismissViewControllerAnimated:NO completion:^{[[NSNotificationCenter defaultCenter] postNotificationName:@"BACKTOMAIN" object:nil];}]; - Lie-An

2
看起来你是在不关闭“first”的情况下将“second”关闭了。
苹果推荐的做法是使用委托。尝试让mainVC成为'first'的代理,这样'first'就可以调用mainVC的方法来关闭自己。当实例化'first'时,声明一个“delegate”属性,并将其设置为mainVC。然后在first.h中定义一个“firstDelegate”协议,其中包括一些函数,如“dismissFirst”,并在mainVC中导入first.h。现在在mainVC中实现dismissFirst以实际关闭“first”,并在完成显示“first”之后执行其他操作。
现在以同样的方式使“first”成为“second”的代理,然后只需使“dismissSecond”函数调用mainVC的“dismissFirst”函数,世界就会恢复正常了。
我知道这有点复杂,但委托是iOS的核心概念,这是它被使用的典型例子。
这里有一个很好的解释,说明了这是如何工作的。 http://chrisrisner.com/31-Days-of-iOS--Day-6%E2%80%93The-Delegate-Pattern 祝你好运,永远探索苹果工程师思维内部机制的奇妙旅程,也就是Obj-C。

1
可以放心地解散已经以链式方式呈现的多个控制器。如果您解散了链中的第一个控制器,所有其他控制器都将被解散。在这种特定情况下,问题是由于呈现样式出现问题所导致的。 - rdelmar
我通过使用HalR提供的代码和一些修改解决了这个问题。我添加了一个通知来关闭其他控制器。 - Lie-An

0
你需要使用一个“取消返回”转场。在你想要进行转场的视图控制器中创建一个“空”的IBAction。
@IBAction func unwindToController(segue: UIStoryboardSegue) {

}

然后进入你的故事板并选择你想要从哪个控制器返回。在所选控制器的顶部图标中,最左边应该是一个黄色圆圈,中心有一个小白色正方形,也就是文件所有者。Ctrl-Drag到你想要返回的视图控制器的“Exit”标签上。Exit可以在控制器树的底部附近找到,或者在Storyboard上作为最右边的红色正方形图像,其中包含带有右箭头的白色正方形。这将弹出一个对话框,请选择你创建的unwindToController操作。

在你的FROM控制器中,会出现一个新的“Unwind segue to Exit”。双击它并给它一个标识符,例如unwindIdentifier

现在当你想要返回两个控制器时,在你的FROM控制器中使用:

self.performSegueWithIdentifier("unwindIdentifier", sender:nil)

这将跳过中间控制器并返回到第二个控制器,动画中只显示 TO 控制器。


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

0

我也曾经有同样的疑问。我用另一种方法解决了这个问题 -

步骤1:在一个全局类(单例)中,您可以定义一个变量标志。

@property (nonatomic) int flag;

步骤 2:假设您需要关闭 第二个视图控制器第一个视图控制器 并返回到 主视图控制器,在关闭第二个视图控制器时,可以将此值设置为 假设1。

[[Global sharedObject] setFlag:1];
[self.navigationController popViewControllerAnimated:YES];

第三步:在您的第一个视图控制器- (void)viewWillAppear:(BOOL)animated方法中,您可以设置此方法 -
if([[Global sharedObject] flag] == 1)
{
    [[Global sharedObject] setFlag:0];
    [self performSelector:@selector(back) withObject:nil afterDelay:0.5];
}

- (void) back
{
[self.navigationController popViewControllerAnimated:YES];
}

希望您的问题已经得到解决。如果您仍有疑问,可以随时提出。祝好 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接