从 iOS 中呈现的视图控制器推送视图

Posted

技术标签:

【中文标题】从 iOS 中呈现的视图控制器推送视图【英文标题】:Push View from Presented View Controller in iOS 【发布时间】:2016-01-04 12:39:28 【问题描述】:

简而言之: 如何从 Presented ViewController PushViewController ?

简介:

我有MainViewController,其中我有一个单击按钮时的按钮,我正在呈现一个名为LoginViewController 的视图。

在此页面 (LoginViewController) 上,我又看到了 button,点击它后,我尝试推送我的视图控制器(称为 HomeViewController),但它没有推送。

这是我的代码 sn-p,

MainViewController.m

- (IBAction)LoginClicked:(id)sender 
    LoginViewController *vc = [[LoginViewController alloc] init];
    [self presentViewController:vc animated:YES completion:nil];

LoginViewController.m

- (IBAction)buttonActionMethodOnLoginView:(id)sender
     NSLog(@"viewControllers %@",APPDELEGATE.nav.viewControllers);
     //LoginViewController is not in this array
     HomeViewController *obj = [[HomeViewController alloc] init];
     [self.navigationController pushViewController:obj animated:YES];

但这对我不起作用。另外,我在pushed 之前打印了a stack of view controllers,但它没有LoginViewController。那么,在不将LoginViewController 添加到a stack of view controllers 的情况下,我如何从LoginViewControllerpushed 转换为HomeViewController

当我从HomeViewController 返回时,LoginViewController 应该会打开..

是否可以使用此单NavigationController

注意:- 在这里,我只是举了一个使用 Login、Home 和 Main ViewController 的例子。但我希望它进入其他屏幕。

【问题讨论】:

LoginViewController 是否实现了UINavigationViewController?您可以尝试使用 self presentViewController 像 LoginViewController 一样推送 HomeViewController 是的,我可以presentHomeViewController。但是,我想从LoginViewControllerpush HomeViewController.. 你的 LoginViewController 必须有它的 NavigationController 才能从 LoginView Controller 推送。 @technerd :是的,但是我该怎么做呢? @MeetDoshi,你检查我的答案了吗?你得到了一些帮助吗? 【参考方案1】:

嗨,当您向您展示登录视图控制器时,只需展示一个导航控制器,例如:

LoginVC *loginVCObj =[[LoginVC alloc]initWithNibName:@"LoginVC" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:loginVCObj];
[self presentViewController:nav animated:YES completion:nil];

现在你的 PresentedViewController 是一个导航控制器 现在你可以简单地推送到你的 Home VC

  HomeViewController *obj = [[HomeViewController alloc] init];
 [self.navigationController pushViewController:obj animated:YES];

希望对你有帮助

【讨论】:

使用这段代码,我可以pushed查看控制器。但是LoginVC 不是dismissed。所以当我解雇LoginVC 时,它会回到HomeViewController。当我pop 这个时,它会回到MainViewController。所以这并没有解决我的问题。 让我解释一下。到我的代码。当您在 mainVC 上并呈现“UINavigationController”导航时。如果你想从 LoginVC 推送到 HomeVC,现在你在不同的 NavigationController 上而不是在前一个上。您的 mainVC 不在此导航中。 好的。但是一个NavigationController怎么能做到这一点呢? @Shubhambairagi 你在完成块里放了什么?天哪【参考方案2】:

LoginViewController 不应被推送到导航控制器堆栈。让我在下面描述“为什么”。

我们的MainViewController 应该在堆栈上 - 你总是想回到那里。

// AppDelegate.m (only if you don't use storyboards, if you do - you don't need to copy this part of code)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
    // create the window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [self.window setBackgroundColor:[UIColor whiteColor]];
    [self.window makeKeyAndVisible];

    // set view controllers
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:[[MainViewController alloc] init]];
    [self.window setRootViewController:navigationController];

在特定动作上显示LoginViewController。您不希望用户能够点击back 并转到MainViewController。稍后,您将不希望用户返回LoginViewController。因此,您需要将其呈现为模态:

// inside `MainViewController.m`
- (IBAction)myCoolActionToShowLogin:(id)sender 
    [self presentViewController:[[LoginViewController alloc] init] animated:YES completion:nil];

现在我们可以看到LoginViewController。当用户完成登录后,将其关闭并显示HomeViewController

// inside `LoginViewController.m`
- (IBAction)myAwesomeActionToShowHome:(id)sender 
    UINavigationController *navigationController = (UINavigationController *)[UIApplication.sharedApplication.keyWindow rootViewController];
    [navigationController pushViewController:[[HomeViewController alloc] init] animated:YES];
    [self dismissViewControllerAnimated:YES completion:nil];

注意事项:

您可能注意到,myAwesomeActionToShowHome: 期望您拥有导航控制器作为您的rootViewController。这是可行的,但应该更好 - 您应该检查该导航是否实际上是导航控制器而不是投射它。或者您可以创建一个代表或块来推送新的。这是最快、最简单的解决方案,以后应该会改进。

真的应该阅读:Apple Developer -> "View Controller Programming" documentation,因为这些是正确开发和设计 UX 的核心基础

这是工作的demo sample。

【讨论】:

正如你没有提到的,我假设你不使用 Storyboards。这仅影响 AppDelegate。如果您使用 Storyboard,则 AppDelegate 中的条目由 Storyboard “完成”,您不必使用该代码。无论如何,剩下的两种方法对于 Storyboard 和 Code 解决方案都是正确的。 这对我不起作用.. 使用这个,当我试图从呈现的视图中推送视图时,当我关闭呈现的视图时,视图控制器推送但从未显示我的推送视图显示的时间。所以,我的问题是,当我从呈现的视图推送视图控制器时,当时我想显示推送的视图控制器而不关闭我呈现的视图.. @MeetDoshi 我已经为你创建了一个工作演示 :) 请查看链接:github.com/natalia-osa/SOFPushPopDemo @MeetDoshi 如果你想回到那个控制器,它不应该通过presentViewController:animated: 呈现,而是通过self.navigationController pushNavigationController: 呈现。导航控制器堆栈将处理前后移动。 present.. 应该仅在您想要显示它而不是“保存在历史记录中”时使用。你似乎对如何使用UINavigationControllerUITabBarController 和管理视图控制器有一些知识上的漏洞。请阅读:developer.apple.com/library/ios/featuredarticles/…. @MeetDoshi 很高兴我能够提供帮助并感谢您的接受。在答案中提供了演示的链接;)【参考方案3】:

您不能从呈现的视图控制器推送。我建议,您应该维护您的导航层次结构。

为此,您应该从您的 MainViewController 中显示 LoginViewController,并且您应该为 MainViewController 传递导航控制器。

- (IBAction)openLogin:(id)sender 
    LoginViewController *loginVC = (LoginViewController *) [self.storyboard instantiateViewControllerWithIdentifier:@"login"];
    [loginVC setReferencedNavigation:self.navigationController];
    [self presentViewController:loginVC animated:YES completion:nil];

然后在 LoginViewController 里面,你应该像这样推送到 HomeViewController,

LoginViewController.h

@interface LoginViewController : UIViewController 
    UINavigationController *refNavigationController;

- (void) setReferencedNavigation:(UINavigationController *)refNavCon;

LoginViewController.m

- (void) setReferencedNavigation:(UINavigationController *)refNavCon 
    refNavigationController = refNavCon;


- (IBAction)openHome:(id)sender 
    [self dismissViewControllerAnimated:YES completion:^
        UIViewController *homeVC = [self.storyboard instantiateViewControllerWithIdentifier:@"home"];
        [refNavigationController pushViewController:homeVC animated:YES];
    ];

通过这样做,看起来您是从 LoginViewController 推送,但实际上您是从 MainViewController 推送。

您可以自定义此方法以维护此流程的动画和 UI。

【讨论】:

它适用于情节提要.. 但是 xib 呢?我想将它实现到 xib 项目中。 为什么? XIB 有什么问题?您只需要更改创建视图控制器对象的方式。 是的,我试过了。但手动我无法将视图控制器添加到导航控制器堆栈中。 您可以查看this、this 和this。这些链接向您展示了如何创建导航控制器并以编程方式附加视图控制器。如果您还需要更多帮助,请告诉我。 我不确定你为什么要这样做。好像不太合适。相反,您的 MainViewController 应该在 UINavigationController 内。因此,您无需在呈现LoginViewController 时重置任何内容。例如。 LoginViewController *controller = [[LoginViewController alloc] initWithNibName:@"LoginView" bundle:[NSBundle mainBundle]];【参考方案4】:

1) 将navigation controller with itsroot 视图控制器设置为视图控制器。

- (IBAction)LoginClicked:(id)sender 

    LoginViewController *loginViewController = [LoginViewController alloc] init];
    UINavigationController *navController = [UINavigationController alloc] initWithRootViewController:loginViewController];
    [self presentViewController:navController animated:YES completion:nil];


- (IBAction)buttonActionMethodOnLoginView:(id)sender

    HomeViewController *obj = [[HomeViewController alloc] init];
    [self.navigationController pushViewController:obj animated:YES];

希望它对你有用。

【讨论】:

【参考方案5】:

问题是LoginViewController 没有导航控制器。那你给它一个。

MainViewController.m

创建一个UINavigationController,将LoginViewController 放入堆栈并呈现UINavigationController

- (IBAction)LoginClicked:(id)sender 
    LoginViewController *vc = [[LoginViewController alloc] init];
    UINavigationController = nav = [[UINavigationController alloc] init];
    nav.viewControllers = @[vc];
    [self presentViewController:nav animated:YES completion:nil];

LoginViewController.m

- (IBAction)buttonActionMethodOnLoginView:(id)sender
    HomeViewController *obj = [[HomeViewController alloc] init];
    [self.navigationController pushViewController:obj animated:YES];

解雇

在您的MainViewController 中致电dismissViewControllerAnimated

【讨论】:

【参考方案6】:

对于 Swift 3.0

将您的视图控制器显示为新的 rootViewController

let navController = UINavigationController.init(rootViewController: self.storyboard!.instantiateViewController(withIdentifier: "SignInViewController"))
self.present(navController, animated: true, completion: )

现在从呈现的视图控制器推送您的视图控制器

self.show(self.storyboard!.instantiateViewController(withIdentifier: "SignUpViewController"), sender: self)

【讨论】:

【参考方案7】:

创建一个 UINavigationController 实例

[[UINavigationController alloc] initWithRootViewController:[[LoginViewController alloc] init]]

显示该导航控制器,然后推送您想要的任何 VC。

【讨论】:

【参考方案8】:

MainViewController.m

 - (IBAction)LoginClicked:(id)sender 

     LoginViewController *vc = [[LoginViewController alloc] init];

     UINavigationController *loginNav = [[UINavigationController alloc] initWithRootViewController:vc]; 

     [self presentViewController:loginNav animated:YES completion:nil];  

 

LoginViewController.m

- (IBAction)buttonActionMethodOnLoginView:(id)sender
     NSLog(@"viewControllers %@",APPDELEGATE.nav.viewControllers);
     //LoginViewController is not in this array
     HomeViewController *obj = [[HomeViewController alloc] init];
     [self.navigationController pushViewController:obj animated:YES];

【讨论】:

这对我不起作用.. 为什么你要展示两次 viewController ?? 是的,是输入错误。现在你可以试试了。它会工作【参考方案9】:

您必须在 firstView (MainViewController) 中使用 Push,但您可以使用与 PresentViewDismissView 相同的动画。为此使用以下代码:-

推送MainViewController

LoginViewController *VC = [[LoginViewController alloc]init];
CATransition* transition = [CATransition animation];
transition.duration = 0.3f;
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromTop;
[self.navigationController.view.layer addAnimation:transition
                                            forKey:kCATransition];
[[[UINavigationController alloc] initWithRootViewController:VC] pushViewController:VC animated:NO];
//[self.navigationController pushViewController:VC animated:NO];

流行音乐LoginViewController

CATransition* transition = [CATransition animation];
transition.duration = 0.3f;
transition.type = kCATransitionReveal;
transition.subtype = kCATransitionFromBottom;
[self.navigationController.view.layer addAnimation:transition
                                            forKey:kCATransition];
[self.navigationController popViewControllerAnimated:NO];

使用此代码,您可以获得与Present-Dismiss ViewControllers 相同的动画。详情请参考this answer。

之后,您可以将您的代码用于Pushing LoginViewControllerHomeViewController

希望,这就是您要找的。任何问题都可以回复我。 :)

【讨论】:

【参考方案10】:

这是当前视图控制器和推送视图控制器的非常简单的代码。

- (IBAction)LoginClicked:(id)sender 
        LoginViewController *objLogicVC = [LoginViewController alloc] init];
        UINavigationController *navPresent = [UINavigationController alloc] initWithRootViewController:objLogicVC];
        [self presentViewController:navPresent animated:YES completion:nil];


- (IBAction)buttonActionMethodOnLoginView:(id)sender
        HomeViewController *objHomeVC = [[HomeViewController alloc] init];
        [self.navigationController pushViewController:objHomeVC animated:YES];

【讨论】:

你没有明白我的意思。请再次阅读我的问题.. 我的主要问题是,当我从 HomeViewController 中返回时,应该打开 LoginViewController..【参考方案11】:

只需将此代码放在 button action

上的 objective c
UIViewController *yourViewControllerName = [self.storyboard instantiateViewControllerWithIdentifier:@"yourViewControllerName "];

[[self navigationController] pushViewController:yourViewControllerName  animated:YES];

【讨论】:

以上是关于从 iOS 中呈现的视图控制器推送视图的主要内容,如果未能解决你的问题,请参考以下文章

如何将视图控制器从视图控制器推送为全屏幕,呈现为半模式

无法呈现/推送另一个视图控制器

iOS 7 在 UINavigationController 中呈现模式视图?

从视图控制器呈现导航视图 - IOS 7

ios:如何关闭模态视图控制器,然后弹出推送的视图控制器

如何在一种情况下推送视图控制器,但在另一种情况下以模态方式呈现它?