Presenting a ViewController breaks the previous ViewController - ios

My problem is when I present a UIViewController the presenting views are going black.
I have a UIViewController named mainViewController which is the root view of my windows.
Inside I have a MMDrawerController (just added as a subview of mainViewController's view).
The MMDrawerController contains the rest of my views.
But when I'm presenting a new UIViewController from my mainViewController, the new VC displays well, but when it dismisses it left only black screen behind.
To note the black screen appears when adding (I can see it directly). Not when dismissing.
For testing purpose I did this code :
UIViewController *vc = [UIViewController new];
vc.view.backgroundColor = [UIColor redColor];
[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:vc animated:NO completion:^{
[vc dismissViewControllerAnimated:YES completion:nil];
}];
Which do the same black result as normal use. (normally it's a QLViewController...)
My mainViewController is set like it :
_mainViewController = [MyMainViewController new];
_window.rootViewController = _mainViewController;
[self.window addSubview:_mainViewController.view];
Souce code of MMDrawerController which is up to date in my project

I have tested the code just in MMDrawerController example project, but I can't reproduce the problem, following is what I have tried:
MMAppDelegate.m
-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//...
UIViewController *testVc = [[UIViewController alloc] init];
testVc.view.backgroundColor = [UIColor greenColor];
[testVc.view addSubview:self.drawerController.view];
[self.window setRootViewController:testVc];
[self.window addSubview:testVc.view];
return YES;
}
MMExampleSideDrawerViewController.m:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {
case MMDrawerSectionViewSelection:{
UIViewController *vc = [UIViewController new];
vc.view.backgroundColor = [UIColor redColor];
UIViewController *mainVC = [[UIApplication sharedApplication] keyWindow].rootViewController;
[mainVC presentViewController:vc animated:YES completion:^{
[vc dismissViewControllerAnimated:YES completion:nil];
}];
return;
//...
}
MMExampleCenterTableViewController.m:
-(void)doubleTap:(UITapGestureRecognizer*)gesture{
UIViewController *vc = [UIViewController new];
vc.view.backgroundColor = [UIColor redColor];
UIViewController *mainVC = [[UIApplication sharedApplication] keyWindow].rootViewController;
[mainVC presentViewController:vc animated:YES completion:^{
[vc dismissViewControllerAnimated:YES completion:nil];
}];
return;
[self.mm_drawerController bouncePreviewForDrawerSide:MMDrawerSideLeft completion:nil];
}

In the end, the problem was that I applied inset constraints on my mainViewController.
Behind the scene I suppose that method presentViewController:animated:completion: use frames and not AutoLayout, which break the UIView of the UIViewController that are in the mainViewController.
Thanks to #simalone, I used the same way to find the origin of the problem (use MMDrawerController example project).
I you want to test yourself the problem, I uploaded the example project with the issue so you can understand it.
There is a breakpoint on the line which is the origin of the bug.
Then just double click on the view.
Thanks again to #simalone. Cheers !

Related

presentViewController(UIViewController) not working

I wanted to populate my uncontrolled view as presentViewController on my app, but it does not work. I do not want to cover the entire screen. Like on the iPad, it should view at the centre and frame, which is preferred.
Below is my code which covers the entire screen:
MyView *testview = [[MyView alloc]init];
testview.modalPresentationStyle = UIModalPresentationFormSheet;
testview.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController: testview animated:YES completion:nil];
I do not want to push my UIViewController...
You cannot present a View. You must present a controller. for example:
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
MyViewController* vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"MY_CTL_ID"];
[self presentViewController:vc animated:NO completion:nil];
Here's what worked for me (iOS 9 or later):
MyViewController *testVC = [[MyViewController alloc] init];
testVC.modalPresentationStyle = UIModalPresentationFormSheet;
testVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
// Both of these are necessary to make it present as a form sheet on an iPhone/iPod.
testVC.presentationController.delegate = vc;
testVC.presentationController.overrideTraitCollection = [UITraitCollection traitCollectionWithTraitsFromCollections:#[[UITraitCollection traitCollectionWithUserInterfaceIdiom:UIUserInterfaceIdiomPad]]];
// Set the size if you don't set it elsewhere.
testVC.preferredContentSize = CGSizeMake(270, 130);
[self presentViewController:vc animated:YES completion:nil];
Also, the view controller you are presenting needs implement the UIAdaptivePresentationControllerDelegate protocol:
#interface MyViewController () <UIAdaptivePresentationControllerDelegate>
...
#end
#implementation MyViewController
...
(UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection {
// This makes it use the presentation style that was set when it was presented.
return UIModalPresentationNone;
}
...
#end

Push View from Presented View Controller in iOS

In Short :
How can I PushViewController from Presented ViewController ?
In Brief :
I have MainViewController, In which I have one button on click of button, I am presenting a view called LoginViewController.
On this page (LoginViewController), I again have button, on click of that, I try to push my view controller(called HomeViewController) it doesn't pushes.
Here is my code snippet,
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];
}
But it did not works for me. Also, I printed a stack of view controllers before pushed, but it doesn't have LoginViewController. So, without adding LoginViewController into a stack of view controllers, How can I pushed to HomeViewController from LoginViewController ?
When I getBack from HomeViewController, then LoginViewController should get opened..
Is it possible using doing this single NavigationController?
Note:- Here, I have just taken an example using Login, Home and Main ViewController. But I want that into Other Screens.
hi when you are Presenting you Login view controller Just present a navigationController like:
LoginVC *loginVCObj =[[LoginVC alloc]initWithNibName:#"LoginVC" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:loginVCObj];
[self presentViewController:nav animated:YES completion:nil];
Now your PresentedViewController is An navigtioncontroller
now you can simply push to your Home VC
HomeViewController *obj = [[HomeViewController alloc] init];
[self.navigationController pushViewController:obj animated:YES];
Hope it will helpful for you
LoginViewController should not be pushed to navigation controller stack. Let me describe below "why".
Our MainViewController should be on the stack - you always want to go back there.
// 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];
}
On specific action show LoginViewController. You don't want the user to be able to tap back and go to MainViewController. Later, you won't want user to go back to LoginViewController. Because of this, you need to present it as modal:
// inside `MainViewController.m`
- (IBAction)myCoolActionToShowLogin:(id)sender {
[self presentViewController:[[LoginViewController alloc] init] animated:YES completion:nil];
}
Now we can see LoginViewController. When user completes the login, dismiss it and present 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];
}
NOTES:
As you may notice, myAwesomeActionToShowHome: expects you have navigation controller as your rootViewController. This is working, but should be nicer - you should check if that navigation is in fact navigation controller instead of casting it. Or you may create a delegate or block to push new one. This is the fastest, easiest working solution, which should be improved later.
You really should read: Apple Developer -> "View Controller Programming" documentation, as these are the core fundamentals you should know to develop & design UX correctly.
Here is the working demo sample.
You can't push from a presented view controller. I suggest, you should maintain your navigation hierarchy.
For that, from your MainViewController, you should present LoginViewController and you should pass navigation controller for the MainViewController.
- (IBAction)openLogin:(id)sender {
LoginViewController *loginVC = (LoginViewController *) [self.storyboard instantiateViewControllerWithIdentifier:#"login"];
[loginVC setReferencedNavigation:self.navigationController];
[self presentViewController:loginVC animated:YES completion:nil];
}
Then inside LoginViewController, you should push to HomeViewController like this,
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];
}];
}
By doing this, it will be look like, you're pushing from LoginViewController but in reality you're pushing from MainViewController.
You can customize this approach to maintain animation and UI for this flow.
1) present a navigation controller with itsroot view controller` set as view controller .
- (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];
}
Hope it will work for you.
The problem is that LoginViewController has no navigation controller. Then you give it one.
MainViewController.m
Create a UINavigationController, put LoginViewController in to the stack and present the 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];
}
Dismiss
Call dismissViewControllerAnimated in your MainViewController.
For Swift 3.0
Present your view controller as a new rootViewController
let navController = UINavigationController.init(rootViewController: self.storyboard!.instantiateViewController(withIdentifier: "SignInViewController"))
self.present(navController, animated: true, completion: {})
Now push your view controller from presented view controller
self.show(self.storyboard!.instantiateViewController(withIdentifier: "SignUpViewController"), sender: self)
Create a UINavigationController instance
[[UINavigationController alloc] initWithRootViewController:[[LoginViewController alloc] init]]
Present that navigationController and then push whatever VC you want to.
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];
}
You have to Push from your firstView (MainViewController), but you can use animation same as PresentView and DismissView. Use following code for this :-
For Push (on 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];
For Pop (on 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];
Using this code, you can get animation same as Present-Dismiss ViewControllers. Refer this answer for more details.
And after that, you can use your code for Pushing LoginViewController to HomeViewController
Hope, this is what you're looking for. Any concern get back to me. :)
This is very simple code for present view controller and push view controller.
- (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];
}
simply put this code in objective c on button action
UIViewController *yourViewControllerName = [self.storyboard instantiateViewControllerWithIdentifier:#"yourViewControllerName "];
[[self navigationController] pushViewController:yourViewControllerName animated:YES];

In iOS 7, using UIModalPresentationCurrentContext for an animated modal presentation doesn't animate

In iOS 8, when presenting a modal (lets say with a transparent background), we need to set the segue (or the modal) to use the presentation style of UIModalPresentationOverCurrentContext. This is working as expected.
To accomplish the same thing for iOS 7, you instead, need to set the presenting view controller to have a modal presentation style of UIModalPresentationCurrentContext. Here's where I'm having an issue. I present the modal with animation, but it doesn't animate. After it is presented, everything works fine, even animating the dismissal. Further, if I change the presentation style to UIModalPresentationFullScreen, it animates correctly.
I've searched around and read other posts, but I can't find the cause of this or a solution.
ViewController *vcObj = [[ViewController alloc] initWithNibName:NSStringFromClass([ViewController class]) bundle:nil];
UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:vcObj];
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
navCon.providesPresentationContextTransitionStyle = YES;
navCon.definesPresentationContext = YES;
navCon.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:navCon animated:NO completion:nil];
}
else {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[self presentViewController:navCon animated:NO completion:^{
[navCon dismissViewControllerAnimated:NO completion:^{
appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:navCon animated:NO completion:nil];
appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationFullScreen;
}];
}];
}

How to return to view controller in main.storyboard from a xib without using navigation controller or navigation bar?

I am making an app with different view controllers. My home screen is in main.storyboard. Rest of the view controllers have their own xib, .h & .m files. I am trying this for navigation from home screen.
-(IBAction)btnSignUpTapped:(id)sender
{
SignUpWithEmailViewController * login = [[SignUpWithEmailViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc]
initWithRootViewController:login];
[self presentViewController:nav animated:YES completion:NULL];
}
This code works fine for navigating to different viewcontroller (in this case SignUpwithEmailViewController). On SignUpWithEmailViewController I have a back button which is supposed to bring me back to home screen. This is what I got so far:
-(IBAction)btnBackTapped:(id)sender
{
ViewController * homeScreen = [[ViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc]
initWithRootViewController:homeScreen];
[self presentViewController:nav animated:YES completion:NULL];
}
But as result of this code, screen turns black and nothing happens. How do I solve this problem? For hiding the nav bar I am using
-(void) viewWillAppear:(BOOL)animated
{
[[self navigationController] setNavigationBarHidden:YES animated:NO];
}
Yes, you have to insert you called viewController to NavigationController,
but if you wont to use modal flow - to close presentedViewController just call:
[self dismissViewControllerAnimated:YES completion:^{
}];
EDITED:
may be it will be more helpful, it just example, put it to you main view controller:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIViewController *c = [[UIViewController alloc] init];
c.view.backgroundColor = [UIColor redColor];
[self presentViewController:c animated:YES completion:^{
[self dismissViewControllerAnimated:YES completion:^{
}];
}];
}

Moving between view by presentViewController. Whats going wrong?

Every time that I press the button activating the action above, my screen goes black.
I just want pass to another view (or same) without using the model proposed by storyboard.
What's wrong?
Thanks
- (IBAction)goToView:(id)sender {
ViewController *controller = [[ViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:controller animated:YES completion:nil];
You haven't configured your controller's view.
For example try this just before you presentViewController...
controller.view.backgroundColor = [UIColor orangeColor];
Your screen will turn orange...
Full example:
- (IBAction)goToView:(id)sender {
ViewController *controller = [[ViewController alloc]
initWithNibName:nil bundle:nil];
controller.view.backgroundColor = [UIColor orangeColor];
[self presentViewController:controller animated:YES completion:nil];
}

Resources