从 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
的情况下,我如何从LoginViewController
将pushed
转换为HomeViewController
?
当我从HomeViewController
返回时,LoginViewController
应该会打开..
是否可以使用此单NavigationController
?
注意:- 在这里,我只是举了一个使用 Login、Home 和 Main ViewController 的例子。但我希望它进入其他屏幕。
【问题讨论】:
LoginViewController
是否实现了UINavigationViewController
?您可以尝试使用 self presentViewController
像 LoginViewController 一样推送 HomeViewController
。
是的,我可以present
那HomeViewController
。但是,我想从LoginViewController
push
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..
应该仅在您想要显示它而不是“保存在历史记录中”时使用。你似乎对如何使用UINavigationController
、UITabBarController
和管理视图控制器有一些知识上的漏洞。请阅读: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 its
root 视图控制器设置为视图控制器。
- (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
,但您可以使用与 PresentView
和 DismissView
相同的动画。为此使用以下代码:-
推送(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
LoginViewController
到HomeViewController
希望,这就是您要找的。任何问题都可以回复我。 :)
【讨论】:
【参考方案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 中呈现的视图控制器推送视图的主要内容,如果未能解决你的问题,请参考以下文章