在当前视图控制器中关闭以前的模态视图控制器

3

我目前有3个视图控制器: LoginViewController, SignUpViewControllerMainViewController

当用户打开应用程序时,将呈现LoginViewController。如果这是用户第一次使用该应用程序,则必须注册,"注册"按钮在LoginViewController中。 "注册" 按钮将弹出SignUpViewController

一旦用户完成注册。 将呈现MainViewController

我的目标是,在MainViewController中会有一个 “登出” 按钮。 当用户按下它时,应取消显示MainViewController并显示LoginViewController。用户不应再次看到SignUpViewController

以下是我的尝试:

1) 在 "注册" 按钮中关闭SignUpViewController并呈现MainViewController

- (void) signUpClicked
{
MainViewController *mainViewController = [viewController.storyboard instantiateViewControllerWithIdentifier:@"MainViewController"];

        [viewController presentViewController:mainViewController animated:YES completion:^{
            [viewController dismissViewControllerAnimated:NO completion:^{

            }];

        }];
}

2) 当 MainViewController 加载时,关闭 SignUpViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    SignUpViewController *signUpViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"SignUpViewController"];
    [signUpViewController dismissViewControllerAnimated:NO completion:^{

    }];

}

当注销按钮被按下时 - 显示LoginViewController。你是否正在关闭不在屏幕上的视图? - Robert J. Clegg
@Tander 如果我这样做,那么会有4个ViewControllers重叠在一起吗?我认为那不是最好的解决方案。 - Ty Lertwichaiworawit
为什么不使用UINavigationController呢?我认为在这种情况下,操作视图控制器的堆栈比呈现和解除它们更简单。 - Andrey Chernukha
@AndreyChernukha 我想这样做。但UINavigationController会让我的设计不太好看。此外,我不想重新设计整个应用程序。 - Ty Lertwichaiworawit
5个回答

5

好的。我将SignUpViewController传递给MainViewController并在MainViewController中取消SignUpViewController。

对于其他和我有相同问题的人。

SignUpViewController.m

- (void) signUpButtonClicked
{
        MainViewController *mainViewController = [viewController.storyboard instantiateViewControllerWithIdentifier:@"MainViewController"];
        mainViewController.signUpViewController = viewController;

        [viewController presentViewController:mainViewController animated:YES completion:^{            
        }];
}

MainViewController.m

- (IBAction)logoutClicked:(id)sender
{

    [self dismissViewControllerAnimated:YES completion:^{

        [self.signUpViewController dismissViewControllerAnimated:NO completion:^{

        }];

    }];
}

1

解决方案:修改当前导航栈

解决这个问题的最简单方法是通过访问导航控制器的导航栈来实现。导航控制器通过将控制器存储在数组中来了解流程,其中它会不断地对控制器进行堆叠。您可以通过在安全的情况下删除不需要的视图控制器来修改此堆栈,该堆栈表示为称为viewControllers(NSArray)的属性。安全的方法是在不是当前视图控制器(或堆栈顶部的视图控制器)之后从数组中删除它,您可以通过查看属性visibleViewController来检查它。

因此,当您已经注册并且正在使用mainViewController时,您的数组应如下所示:[loginVC,SignUpVC,MainVC]

这意味着MainVCvisibleViewController,只要您保持相同的visibleViewController作为数组的最后一项,就可以安全地修改导航栈。

因为 viewControllers 不是可变数组,所以只需将这个 [loginVC,MainVC] 数组分配给它即可。我建议至少浏览一下 UINavigationController 的文档。


1

presentViewController可以帮助你完成很多工作,但也许你应该自己创建一个Container View Controller。它们非常容易!UIViewController上的UIContainerViewControllerProtectedMethods类别概述了你可以/应该使用的方法。

基本思路是您有一个容器View Controller,它将子View Controllers添加到自身以及它们的视图作为自己视图的子视图。主要承担重力的方法是:

...   transitionFromViewController:(UIViewController *)fromViewController
                  toViewController:(UIViewController *)toViewController
                          duration:(NSTimeInterval)duration
                           options:(UIViewAnimationOptions)options
                        animations:(void (^)(void))animations
                        completion:(void (^)(BOOL finished))completion

在动画部分,您可以进行任何类型的移动。在您的情况下,您希望将LoginViewController的视图放在MainViewController的视图后面,并将MainViewController的视图移出屏幕。您可以提供自己的动画选项,因此外观将类似于现在的dismissViewController。
设置有点复杂,但视图控制器容器为您提供了很多灵活性和功能。

1
这不是您的问题的一部分,但您应该考虑使用UINavigationController,因为您很可能需要从您的MainViewController显示新视图。
我会使用如下架构:
  • UINavigationController
    • LoginViewController (RootViewController)
      • SignupViewController (Modal)
    • MainViewController (Push)
所以您的第一个视图控制器是LoginViewController
在您的SignupViewController中,您实现了下一个协议:
@class SignupViewController;
@protocol SignupViewControllerDelegate : NSObject
@required
 - (void)signupViewController:(SignupViewController*)viewController didSignupWithData:(id)customData;
 - (void)signupViewControllerDidCancel:(SignupViewController*)viewController;
@end

“customData”对象仅在您需要从“SignupViewController”传递数据到“MainViewController”时才有用。
您可以将此属性添加到您的“SignupViewController”中。
@interface SignupViewController : UIViewController
@property (nonatomic, assign) id <SignupViewControllerDelegate> delegate;
...
@end

您的LoginViewController现在必须实现您刚刚创建的协议。

@interface LoginViewController : UIViewController <SignupViewControllerDelegate>
...
@end

你应该像这样实现这些方法:

And you should implement those methods like this

@implementation LoginViewController

- (void)signupViewController:(SignupViewController*)viewController didSignupWithData:(id)customData {
    // You can dismiss the SignUpViewController before pushing your next view
    [self dismissViewControllerAnimated:NO completion:^{
        // You can store the data you received from the SignupViewController

        // Push your next view controller here
        [self performSegueWithIdentifier:@"myIdentifier" sender:nil];

        // Or this if you don't use Storyboard
        MainViewController *vc = [[MainViewController alloc] initWithCustomData:customData];
        [self.navigationController pushViewController:vc animated:YES];
    }];
}

- (void)signupViewControllerDidCancel:(SignupViewController*)viewController {
        // The user canceled the Signup operation, just dismiss the viewController
        [self dismissViewControllerAnimated:YES completion:nil];
}

@end

我正在解释一下这段代码 ^^ 在你的SignupViewController中,当用户点击结束注册流程的按钮时,你调用了这个方法。
[self.delegate signupViewController:self didSignupWithData:myCustomData];

或者如果他取消了

[self.delegate signupViewControllerDidCancel:self];

使用这种方法,当你展示 MainViewController 时,你的 SignupViewController 将被移除。当用户退出登录时,你需要在 MainViewController 中调用此方法:
[self.navigationController popViewControllerAnimated:YES];

由于您的 SignupViewController 已被关闭,因此您将直接重定向到 LoginViewController 。


0

这对我有用;把顺序搞对非常繁琐。

DestinationViewController *vc = [[UIStoryboard storyboardWithName:@"Main_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:@"DestinationView"];

UIViewController* presentingViewController = self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
    [presentingViewController presentViewController:vc animated:YES completion:nil];

}];

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