I've got an app that is a list of itens in a table view and displays a detail view controller to every item on the table view. It also implements MMDrawerController (root view controller) as a side menu with storyboard.
I'm deep linking my app and using application open URL source application annotation method from App Delegate to handle it. So, I want to push a detail view controller from this method using MMDrawerController and I'm having some trouble.
Have a look in some code:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
DetalheRestauranteViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"detalheRest"];
MMDrawerController* drawerController = (MMDrawerController *)self.window.rootViewController;
// If I use this nothing happens
[drawerController.centerViewController.navigationController pushViewController:vc animated:YES];
// If I use this nothing happens
[((MMDrawerController *)self.window.rootViewController).centerViewController.navigationController pushViewController:vc animated:YES];
// If I use this I got the unrecognized selector error
[(UINavigationController*)self.window.rootViewController pushViewController:vc animated:NO];
return YES;
}
Can someone help me with this?
I have found that with deep linking and the new iOS9 menu shortcuts that a small delay is often needed to display or manipulate UI Components.
I would try moving all of your UI/MMDrawer code to its own method. Then when openURL is called in your app delegate, call your new method on a delay.
So in ObjC it would look something like this:
[self performSelector:#selector(showDetailView) withObject:nil afterDelay:0.3];
do you solve this problem?
I tried many times. Finally I found it works fine for me today:
[((UINavigationController *)((MMDrawerController *)self.window.rootViewController).centerViewController) pushViewController:viewController animated:YES];
or
MMDrawerController *mvc = (MMDrawerController *)self.window.rootViewController;
UINavigationController *nvc = (UINavigationController *)mvc.centerViewController;
[nvc pushViewController:vc animated:YES];
These two kinds of writing are the same.
Here vc is one DetalheRestauranteViewController instance.
Related
I am making a messaging app on ios that will have multiple folders for different types of messages. I will be using a navigation controller structure and would like the root view to be where the user can choose which folder to view. However, when I first segue to the navigation controller I would like the inbox folder view to display directly (ie. bypass the root view). Apples mail app has a similar structure (launches inbox when it opens). how can I do this?
It really depends on how the relationship is between the first view controller and the second view controller. If you want to do something like this, why don't you put your second view controller as the root controller of the UINavigationController.
Anyway, if you still want to do it the way you describe, you can just direct to the second view controller using the viewDidLoad method from your root view controller. But, it will make the UI looks clumsy.
try to use this code :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UIStoryboard *board = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController *controller1 = [board instantiateViewControllerWithIdentifier:#"firstView"];
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController:controller1];
SecondViewController *secondView = [board instantiateViewControllerWithIdentifier:#"secondView"];
[controller1 addChildViewController:secondView];
[self.window setRootViewController:navController];
return YES;
}
Hope this will help you.
Write this code in didFinishLaunchingWithOptions of AppDelegate.m
UIStoryboard *MainStoryboard = [UIStoryboard storyboardWithName:#"Main"
bundle: nil];
UINavigationController *controller = (UINavigationController*)[MainStoryboard
instantiateViewControllerWithIdentifier: #"YourStoryBoardID"];
NeededViewController *need=[MainStoryboard instantiateViewControllerWithIdentifier:#"YourStoryboardID"];
[controller setViewControllers:[NSArray arrayWithObject:need] animated:YES];
self.window.rootViewController=controller;
I am using a storyboard in Xcode 5, which appears as so:
My requirement is to push a ViewController (VIEW1 or VIEW2) into view from the app delegate. Essentially it should not matter what view is presently on the screen -- I would just like to make a ViewController appear when the app delegate picks up an external event.
In order to try and achieve this, I have property references to both the TabBarCtrl-Products and NavCtrl-ProductA in my app delegate.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
_tabBarProducts = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"sidTabBarProducts"];
NSArray *tabvcs = _tabBarProducts.viewControllers;
for (id controller in tabvcs){
if ([controller isKindOfClass:[VCNavControl_ProductA class]]) {
_navControllerProductA = controller;
break;
}
}
return YES;
}
The app delegate method to push VIEW2 is:
-(void)showVCVIEW2
{
VC_V2 *targetvc = nil;
targetvc = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"sidView2"];
[[AppDelegate sharedInstance].navControllerProductA pushViewController:targetvc animated:NO];
}
This works OK when VIEW1 is showing at the time showVCVIEW2 is called, however it does not work when ViewCtrl-ProductB is showing. I can see that the new instance of targetvc has been added to the AppDelegate _navControllerProductA's stack, however it does not display.
(Regarding the setting of the the app delegate's rootViewController, I set this to _tabBarProducts after the VC-Splash and VC-Setup ViewCtrls have finished).
I would appreciate very much if anyone can give me an idea on how to achieve this. I suspect my problems stem from having a NavCtrl in a TabBarCtrl, but I do not know a way around this.
Your problem is that the navigation controller you are pushing on is not in the view hierarchy.
You instead could try setting the tabBarController's selected index like this:
[self.tabBarController setSelectedIndex:1];
My app has to have a launch screen where I perform some operations such as updating web content. After the process is done, I display the whole app interface within a UITabBarController. At some point, the app has to go back to this launch view controller to handle the update of the application data.
Apple specifically states that a UITabBarController should be the root view controller of any app.
I'm looking for clever ways of presenting a UIViewController before a UITabBarController without embedding both of them in a UINavigationController.
I currently have the setup I want to avoid (UINavigationController -> UITabBarController) because it works and makes sense. I'm afraid Apple wont like it, so i'm looking forward for some light in the subject.
However, nothing that I've read says that the root controller has to remain the same throughout the life of the app. What about something like...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.tabController = (UITabBarController *)[self.window rootViewController];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.altController = [storyboard instantiateViewControllerWithIdentifier:#"AlternateController"];
return YES;
}
- (void)swapRootControllers {
if ([[self.window rootViewController] isKindOfClass:[UITabBarController class]]) {
self.window.rootViewController = self.altController;
} else {
self.window.rootViewController = self.tabController;
}
}
...assuming all the supporting variable declarations and storyboard implementation.
I recently work on a tutorial for my app. I created the tutorial with this Tutorial:
http://www.appcoda.com/uipageviewcontroller-tutorial-intro/
I created a "button" which brings the user back to the rootViewController, in this case the TabBarController. Problem is: with this tutorial I made a extra storyboard for the tutorial. So how can I go back to the original rootViewController(TabBarController) with the button?
Code:
- (IBAction)start:(id)sender {
UIViewController* backToRootViewController = [[UIViewController alloc] initWithNibName:#"TabBarController" bundle:[NSBundle mainBundle]];
[self.view addSubview:backToRootViewController.view];
}
This does not work, too
- (IBAction)start:(id)sender {
[self.navigationController popToRootViewControllerAnimated:YES];
}
EDIT
To open the tutorial at the first start:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL isAccepted = [standardUserDefaults boolForKey:#"iHaveAcceptedTheTerms"];
if (!isAccepted) {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[APPViewController alloc] initWithNibName:#"APPViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
}
APPViewController is the Tutorial
EDIT
After the help of johnnelm9r the current code is this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"main" bundle: nil];
IntroViewController *introViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"IntroViewController"];
BOOL isAccepted = [standardUserDefaults boolForKey:#"iHaveAcceptedTheTerms"];
if (!isAccepted) {
[self.window.rootViewController presentViewController:introViewController animated:NO completion:nil];
}
But now, sadly, the app crashed and the error is:
Application tried to present a nil modal view controller on target <UITabBarController: 0x175409d0>.'
and also a warning: Incompatible pointer type assigning to 'ViewController' from 'UIViewController' in AppDelegate
*****UPDATE****
I uploaded a sample project to demonstrate what I mean. You can find it here: github link
Good luck!
**** EDIT
After talking with you more I'd suggest trying to use something similar to this code in your viewDidAppear method of whatever view controller runs the first tab of your tabbarcontroller (obviously you want your own class name where I have IntroViewController):
BOOL didShowIntro = [[NSUserDefaults standardUserDefaults] boolForKey:#"showIntro"];
IntroViewController *introViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"IntroViewController"];
if (didShowIntro)
{
[self presentViewController:introViewController animated:NO completion:nil];
}
and then just pop the presented controller from your button in the tutorial like so:
[self dismissViewControllerAnimated:NO completion:nil];
Just remember to set your user defaults to no when you press the button in your tutorial view controller. And make sure you are going from tabbarcontroller to navigationcontroller as a relationship segue and then to the view controller you want to show after the tutorial as a root. Just to be clear: there should be no connection to the tutorial view controller on your storyboard.
Just to be extra clear: your storyboard should have the navbarcontroller as your initial view controller connected to a navigationcontroller connected to a view controller and another view controller not connected to anything. :) And make sure you delete the code in the delegate.
To go to rootViewController
[self.navigationController popToRootViewControllerAnimated:YES];
My app consists of a navigation controller and view controllers. Some parts of my UI is done on storyboard and some are initiated from code (in viewDidLoad). My goal is to load childViewController X (consists of a back button, nag bar, label and table) when the app is launched from a push notification "properly" through this method in appDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
This might be a simple question to you guys but I've asked several questions the pass few days (you can look at my questions history). After trying several methods, my app either:
crashes
loads without navigation bar
loads with navigation bar but no label (back button does not work)
loads with navigation bar but with black screen underneath
Only the tableView is dragged onto storyboard. The navigation bar is inferred but I have code that dictates its back button and title. The rest is all done through code in the .m file.
I know people have asked this question before but none of the methods worked. How can I load this childViewController properly through a push notification?
EDIT/UPDATE:
My code so far:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSDictionary *dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (dictionary != nil)
{
UIStoryboard *mainstoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController* firstVC = [mainstoryboard instantiateViewControllerWithIdentifier:#"NotificationsViewController"];
[self.window.rootViewController addChildViewController:firstVC];
[(UINavigationController *)self.window.rootViewController pushViewController:firstVC animated:NO];
self.window.rootViewController.childViewControllers);
}}
Error Code:
'-[SWRevealViewController pushViewController:animated:]: unrecognized selector sent to instance 0x14575f20'
SWRevealViewController is my library for my sidebar menu view controller.
UPDATE2:
I've also tried this method:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *initViewController = [storyboard instantiateViewControllerWithIdentifier:#"NotificationsViewController"];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = initViewController;
[self.window makeKeyAndVisible];
This loads the correct viewController but without a navigation bar.
Try this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDictionary *dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(dictionary != nil) {
UIStoryboard *mainstoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *firstVC = [mainstoryboard instantiateViewControllerWithIdentifier:#"NotificationsViewController"];
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
// Navigation already created
if(navigationController) {
[navigationController pushViewController:firstVC animated:NO];
// Navigation not created
} else {
UINavigationViewController *navigationController = [[UINavigationViewController alloc] initWithRootController:firstVC];
[self.window setRootViewController:firstVC];
[self.window makeKeyAndVisible];
}
}
return YES;
}
You had some problem in your code:
You need to have a UINavigationController in order to have a navigation bar and manage the push/pop actions, so your window root controller should be a UINavigationController.
If you need to initialize a UINavigationController the best and simple way is to initialize it with a root controller directly, so leave the push/pop for user actions: an application has always a root controller, so why don't you create it immediately?
The "addChildController" is another thing: it is used to create custom container controller, it means that you have to implement all the business logic manually. I suggest you to use it only if you are experienced enough, since it could be difficult - Cocoa has enough components to leave it for a small set of applications.
You are using a third part controller, the "SWRevealViewController". They should have an example project, you can try to "copy" it and them customize it for your own purpose.
Let me know if your code works well, otherwise post the new error and I'll try to help you