Open ViewController With SWReveal Gesture from AppDelegate - ios

I am developing an iOS app and using storyboards. In my storyboard, I had set a SWRevealViewcontroller and it works fine.
Now i have a new requirement, and i need to present a viewcontroller, which is an option from the rear_vc in the reveal from my appdelegate, after receive a push notification.
In appdelegate i'm using the next method to instantiate and show the view controller
- (void)showViewController {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
TheViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"vc"];
[self.window makeKeyAndVisible];
[self.window.rootViewController presentViewController:vc animated:YES completion:NULL];
}
So, since the viewcontroller is an option from the rear viewcontroller, i need to add gesture recognizer to display menu using
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
[self.view addGestureRecognizer:self.revealViewController.tapGestureRecognizer];
This is where i have the problem, because self.revealViewController is nil, and the app crashes in this lines, because segue is not coming directly from the rear viewcontroller.
In rear viewcontroller prepare for segue method we need to add this lines
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ( [segue isKindOfClass: [SWRevealViewControllerSegue class]] ) {
SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;
swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {
UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
[navController setViewControllers: #[dvc] animated: NO ];
[self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
};
}
}
But from appdelegate i can't do that, how can achieve this ?
Thanks

Related

MMDrawerController where I need to add sidemen buttons?

I am junior iOS dev and trying to use MMDrawerController.
I have MainStoryboard with 4 views.
NavigationController (embed on CenterViewController controller)
CenterViewController
LeftViewController
AboutViewController
I've added button on Navigation left item on CenterViewController and tap on it open/close my sidemenu.
But if I wan't to change center view with this code
ViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"AboutViewController"];
if (vc)
[appDelegate.drawerController setCenterViewController:vc withCloseAnimation:YES completion:nil];
It works fine but I have no navigation left button. Why?
Thanks
My solution is:
AboutViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"AboutViewController"];
if (vc)
{
if ( [appDelegate.drawerController.centerViewController isKindOfClass:[UINavigationController class]] )
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UINavigationController *navController = (UINavigationController *)appDelegate.drawerController.centerViewController;
[appDelegate.drawerController toggleDrawerSide:MMDrawerSideLeft animated:YES completion:nil];
[navController pushViewController:vc animated:YES];
}
}

PushViewController in fullscreen

I'd like to know if it's possible to push a ViewController of the NavigationController in full screen without tabbar and navigation bar. My problem is as follow:
My app has a NavigationController embedded in a TabBarController. In the NavController I show a FirstVC with a button to navigate to another VC. Right now I do a modal presentation to show the SecondVC. But in this SecondVC I have a tableview where a button returns a ThirdVC. This ThirdVC needs to have the navigationbar and tabbar of the FirstVC. Maybe I need to show the SecondVC with a push on the NavigationController of the first but it seems that I can't reproduce my full screen animation ...
To make it simple:
FirstVC ===> SecondVC (modal presentation) ====> ThirdVC (modal presentation):
This is my app at this time without navbar or tabbar on the ThirdVC.
Thanks in advance.
Edit
The modal presentation to the SecondVC is like that:
- (IBAction)detailButtonClicked:(id)sender {
SecondVC *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondVC"];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:vc animated:YES completion:nil];
}
From the SecondVC to the ThirdVC I use again presentViewController because I can't use pushViewController in modal. The result is predictable: I don't have a navigation bar or a tabbar.
I tried different things like the one below or addChildView as subview to my FirstVC:
- (IBAction)detailButtonClicked:(id)sender {
SecondVC *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondVC"];
UINavigationController *childNavigationController = [[UINavigationController alloc] initWithRootViewController:vc];
childNavigationController.navigationBarHidden = YES;
[self.navigationController presentViewController:childNavigationController animated:YES completion:nil];
}
and in the SecondVC
- (IBAction)changeButtonClicked:(id)sender {
ThirdVC *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"ThirdVC"];
[self.navigationController pushViewController:vc animated:YES];
}
I can't access my tabbar or navigation bar in the ThirdVC either...
What I do in your is I added following code improvement.
- (IBAction)buttonClicked:(id)sender {
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main"
bundle: nil];
SecondViewController *vc = (SecondViewController*)[mainStoryboard
instantiateViewControllerWithIdentifier: #"SecondVC"];
vc.delegate = self;
[[APP_DELEGATE window] addSubview:vc.view];
[self addChildViewController:vc];
}
Main line of code is addchildViewController.
Here You can download the sample code of yours.

prepareForSegue: sender: not being called in app with a menu using SWRevealViewController

I have an app with a sidebar menu using SWRevealViewController. I followed this tutorial on how to make it, but have a problem. I have many subviews of the first subview that has the prepareForSegue: sender: method. In my subclass view controller, I have the implementation:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
do Saving....
[super prepareForSegue:segue sender:sender];
}
The saving never gets called. I put an NSLog() statement and it was never executed. My layout is the same as the video tutorial (modified for my own app, different view controllers for each table cell). Any help?
Try this
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SecondViewController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
[navController setViewControllers: #[rootViewController] animated: YES];
It work for me
Or else follow this tutorial you will find solution.
SWReavalview Controller
Try This
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue isKindOfClass:[SWRevealViewControllerSegueSetController class] ]){
UIViewController *dvc = [segue destinationViewController];
UINavigationController *navCtrl = (UINavigationController *) self.revealViewController.frontViewController;
[navCtrl setViewControllers:#[dvc] animated:NO];
[self.revealViewController setFrontViewPosition:FrontViewPositionLeft animated:YES];
}

What is the best practice to switch between view controllers for iOS in Objective-C

What is the best practice to switch between UIViewControllers for iOS in Objective-C? Now I have a menu UIViewController and a game's main screen UIViewController. In the menu there's a "New game" UIButton which should switch to the game's main controller. I do it like this:
- (IBAction)newGameButtonClicked:(id)sender {
ViewController *gameViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"GameViewController"];
[self presentViewController:gameViewController animated:NO completion:^{
// ...
}];
}
When player dies, other view controller should be showed and I do it in the similar way like this:
MenuViewController *menuViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"MenuViewController"];
[self presentViewController:menuViewController animated:NO completion:^{
// ...
}];
Is it right or there is a better way to achieve this behavior?
Thanks in advance.
If you want to init an UIViewController from the UIStoryboard you can do it like in your example. I would just use a UINavigationController as parent UIViewController and push them to the UINavigationController.
NSString *strVC = [NSString stringWithFormat:#"%#", [MenuViewController class]];
MenuViewController *menuViewController =
[self.storyboard instantiateViewControllerWithIdentifier:strVC];
[self.navigationController pushViewController:menuViewController
animated:YES];
When using segues like #mehinger explained, use [segue destinationViewController]. But this is just needed if you want to set any variables to the UIViewController before pushing it.
If you're in a Navigation Controller:
ViewController *viewController = [[ViewController alloc] init];
[self.navigationController pushViewController:viewController animated:YES];
or if you just want to present a new view:
ViewController *viewController = [[ViewController alloc] init];
[self presentViewController:viewController animated:YES completion:nil];
If you want to present a new viewcontroller in the same storyboard,
In CurrentViewController.m,
import "YourViewController.h"
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
YourViewController *viewController = (YourViewController *)[storyboard instantiateViewControllerWithIdentifier:#"YourViewControllerIdentifier"];
[self presentViewController:viewController animated:YES completion:nil];
or if you are using navigation controller:
[self.navigationController pushViewController:viewController animated:YES];
To set identifier to a view controller, Open MainStoryBoard.storyboard. Select YourViewController View-> Utilities -> ShowIdentityInspector. There you can specify the identifier.
Segues are the way to do when switching between view controllers:
- (IBAction)newGameButtonClicked:(id)sender {
[self performSegueWithIdentifier:#"goToGameViewController"];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if(segue.identifier isEqualToString:#"goToGameViewController") {
GameViewController *gameViewController = [GameViewController new];
//do any other preparation you would like
}
}
In your storyboard you can then drag a segue from one view controller to the other and indicate its identifier as "goToGameViewController".

SWRevealViewController - manually switch to another view?

I have a sidebar menu, made with SWRevealViewController.
One of menu elements in sidebar is "sign-in". It opens sign-in view (via custom SWRevealViewController segue).
I want to programmatically switch to another view after user successfully signs in. How do I do that?
UPDATE, my code:
ViewController *vc = [[ViewController alloc] init]; // this is main front ViewController
SWRevealViewController *revealController = self.revealViewController;
[revealController setFrontViewController:vc animated:YES];
After this I get just empty screen. What am I doing wrong? I feel that this is wrong:
ViewController *vc = [[ViewController alloc] init];
so what is correct way to access already loaded view controller? (it loads at app start by SWRevealViewController as front controller)
Try this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SecondViewController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
[navController setViewControllers: #[rootViewController] animated: YES];
[self.revealViewController setFrontViewController:navController];
[self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
work for me :-)
Use
- (void)setFrontViewController:(UIViewController *)frontViewController animated:(BOOL)animated; method
SWRevealController has it's own property you can access from any UIViewController:
SWRevealViewController *revealController = self.revealViewController;
You can check example projects at it's GitHub repository:
https://github.com/John-Lluch/SWRevealViewController
Here is a Swift version of the setFrontViewController solution:
if let secondViewController = self.storyboard?.instantiateViewControllerWithIdentifier("SecondViewControllerStoryBoardID") as? SecondViewController {
let navController = UINavigationController(rootViewController: secondViewController)
navController.setViewControllers([secondViewController], animated:true)
self.revealViewController().setFrontViewController(navController, animated: true)
}
Try this:
ViewController *vc = [[ViewController alloc] init]; // this is main front ViewController
UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
[navController setViewControllers: #[vc] animated: YES];
// [navController pushViewController:vc animated:YES]; // use this if you want to stack the views
[self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
There is a new API - (void)pushFrontViewController:(UIViewController *)frontViewController animated:(BOOL)animated;
As far as I know, this is the most elegant way that animates correctly to switch between view controllers manually.
// get the view controller you want to push to properly.
// in this case, I get it from Main.storyboard
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController * vc = [sb instantiateViewControllerWithIdentifier:#"SignInViewController"];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:vc];
[navController setViewControllers: #[vc] animated:NO];
[self.revealViewController pushFrontViewController:navController animated:YES];
If you are in the target vc that doesn't import SWRevealViewController and want to push back:
// get your vc properly
[self.navigationController setViewControllers:#[vc] animated:YES];
Please notice that [self.navigationController showViewController:vc sender:self]; has the same result, but don't use this since this creates a new view controller on the navigation stack, which is basically meaningless while using SWRevealViewController.
This one works for me perfectly
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
UINavigationController *navController = [storyboard instantiateViewControllerWithIdentifier:#"NavController"];
[navController setViewControllers: #[rootViewController] animated: YES];
[self.revealViewController setFrontViewController:navController];
[self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
#Evana has a good answer, however for my case which passing parameter to the destViewController, I need to improve it as below. By following her example exactly, I noticed the DestViewController viewDidLoad was called twice. First with 0 on the 'selectedId', only the second call did the 'selectedId' is receiving my tag value.
Thus, in order for a cleaner navigation, the DestViewController must be obtained from the navController, so that there is no redundant call.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UINavigationController *navController = [storyboard instantiateViewControllerWithIdentifier:#"DestNavController"];
DestViewController *destViewController = (DestViewController*)[[navController viewControllers] objectAtIndex:0];
destViewController.selectedId = ((UIButton*)sender).tag;
[self.revealViewController setFrontViewController:navController];

Resources