I'm fairly new iOS development. I have multiple viewControllers for my app, for example -
A login screen
A main / my profile screen
A leader board / standings screen
etc..
Each of these screens has its own viewController.
What's the best way to transition between any two arbitrary viewControllers with an animation?
My current approach is -
Keep a reference to each viewController in AppDelegate.m
Keep changing the window's root controller as needed
This is both cumbersome and seems pretty inefficient, plus I'm not quite sure how to incorprate animated transitions here.
I see some examples with UINavigationController, but it seems like that operates as a "stack" of views that you can go into and then back out of. I'm not looking to keep a history here, just switch from any view to another.
Any good ways to accomplish this?
Thanks!
Try this Code.
AppDelegate.h
#import <UIKit/UIKit.h>
#import "LoginViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong,nonatomic) UINavigationController *navigationController;
#property (strong,nonatomic) LoginViewController *loginVC;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "LoginViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.loginVC = [[LoginViewController alloc]initWithNibName:nil bundle:nil];
self.loginVC.title = #"Login Page";
self.navigationController = [[UINavigationController alloc]initWithRootViewController:self.loginVC];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
}
LoginViewController.h
#import <UIKit/UIKit.h>
#import "MyProfileViewController.h"
#interface LoginViewController : UIViewController
#property (strong,nonatomic)MyProfileViewController *myProfileVC;
#end
Login button action in LoginViewController.m file
- (IBAction)pushMyProfileView:(id)sender
{
self.myProfileVC = [[MyProfileViewController alloc]initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:self.myProfileVC animated:YES];
}
Basically you can achieve that by using:
Apple containers (UINavigationController, UITabbarController, UISplitController)
Containment API
Using "normal" view controller and modal presentation
Containment API is probably what you are looking for, you create a UIViewController that is responsible to manage the presentation of its child view controllers. Here is Apple Documentation, there are plenty of examples inside.
As a beginner I believe the easiest solution for you it to use a Storyboard and create a segue between your View Controller.
Inside your ViewController you should override prepareForSegue: method to pass data to the segue.destinationViewController
Related
I saw my iOS app isn't allowed to be downloaded from the app store with the most recent upgrade to iOS 11, so I'm trying to update it. I have it in Xcode 9, and I've managed to now get the app started on my iPhone 6. However, I can't seem to get it to display after my initial screen display.
For example, the initial display successfully displays and shows a button called "start". That should pop up another display when you press it, but it doesn't (although it is reaching the code which displays it).
Here's the code, in a class named "StartController.m", which should be calling up the display:
NSLog(#"nav controller = %#", self.navigationController);
// push question controller onto the stack
[self.navigationController pushViewController:questionController animated:YES];
// the nav controller owns it now, we can release it
[questionController release];
Debugging shows this code is successfully called when the button is pressed, but after the release of questionController, nothing happens.
Here's the declaration of the questionController in StartController.h:
#interface StartController : UIViewController <ADBannerViewDelegate>{
QuestionController *questionController;
And here's the declaration of the same in StartController.m:
#implementation StartController
#synthesize questionController, settingsController, nextLevelViewController, appState;
The initial view (with the "start" button) is successfully displayed with this code in the "didFinishLaunchingWithOptions" method of the app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// create the start controller
self.startController = [[StartController alloc] init];
// transfer to it - not animated because it's the first view
[navController pushViewController:startController animated:NO];
// add the current nav controller view to the window view heirarchy
// [window addSubview:navController.view];
[self.window setRootViewController:startController];
// release becasause now the navController has it
[startController release];
// show the start controller
[self.window makeKeyAndVisible];
return YES;
}
For reference, here's the declaration of the navController in the app delegate header:
#interface QuizAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UINavigationController *navController;
StartController *startController;
}
#property (readonly) BOOL iPad;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) StartController *startController;
#property (nonatomic, retain) IBOutlet UINavigationController *navController;
And here's the declaration in the implementation:
#implementation QuizAppDelegate
#synthesize window;
#synthesize startController;
#synthesize navController;
I tried not to post too much code for fear of obscuring the problem, but I'll add it if requested. Any ideas what the problem might be?
I'm not using a storyboard or anything. I'm just creating the cocoa classes and linking them up individually. I can get to load up the default View Controller which is SplashViewController but i can't get past there.
I have experience in php, android programming and python, but i'm totally clueless on how Obj-C and how the iOS framework works :(
SplashViewController.m
-(void)initializeInterface
{
//Initialize start button
[self.startButton addTarget:self action:#selector(startActivity) forControlEvents:UIControlEventTouchDown];
//Initialize fading backgrounds
[self animateImages];
}
-(void)startActivity
{
PhoneViewController *phoneView = [[PhoneViewController alloc] initWithNibName:#"PhoneViewController" bundle:nil];
[self.navigationController pushViewController:phoneView animated:YES];
}
SplashViewController.h
#import <UIKit/UIKit.h>
#import "PhoneViewController.m"
#class PhoneViewController;
#interface SplashViewController : UIViewController
#property (strong, nonatomic) PhoneViewController * phoneViewController;
#property UIImage *splashbg1;
#property UIImage *splashbg2;
#property (nonatomic, retain) IBOutlet UIImageView *splashbg;
#property (nonatomic, retain) IBOutlet UIButton *startButton;
-(void)initializeInterface;
-(void)animateImages;
-(void)startActivity;
#end
EDIT
classAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
//Move from delegate view controller to root view controller
self.window.rootViewController=[SplashViewController new];
[self.window makeKeyAndVisible];
return YES;
}
Wrap your splash view controller in a navigation controller.
Otherwise, the navigationController property of your splash view controller is nil and pushViewController has no effect.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController: splashViewController];
To move from one UIViewController to other UIViewController, you can try the following things
If SecondViewController *secondViewController is the UIViewController you want to move in to, then your can do the following:
[self presentViewController: secondViewController animated:YES completion:nil];
This is when you UIViewController is not embedded inside a UINavigationController.
It is possible to create your view controllers entirely in code without using Storyboards or XIB files, but it's not recommended. It's like trying to write a complex user application in assembler. The state of the art has evolved since the days when that was necessary. There are better tools. Use them.
Creating everything yourself is both quite complex and not very well documented. You are setting yourself up for a very frustrating, error-prone process. I've been doing iOS development pretty much full time since 2009, and I would not attempt this.
That being said, if you are a masochist, you would create your view controller using initWithNibName:bundle:, passing in nil for both parameters, and then implement the loadView method. In loadView you're create your view hierarchy and install it.
If you are new to iOS/Objective-C, DO NOT DO THIS. It is like trying to write a kernel device driver in machine code as your first foray into UNIX.
Change you AppDelegate method as below -
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
UINavigationController *navcon = [[UINavigationController alloc]initWithRootViewController:[SplashViewController new]];
//Move from delegate view controller to root view controller
self.window.rootViewController=navcon;
[self.window makeKeyAndVisible];
return YES;
}
Problem in your code, you have not taken any navigationController, that enables you push or pop UIViewController. Doing above you can use your method -(void)startActivity to Start a new ViewController.
Getting the above error when my app launches. The following code is from my AppDelegate .h File
#import <UIKit/UIKit.h>
#interface TableViewAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#end
The following is from my AppDelegate implementation file .m applicationdidfinishlaunchingwithoptions
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//Configure and show the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
return YES;
}
add this in your app delegate:
self.window.rootViewController = navigationController;
If you started with an empty template and added a storyboard, you need to do a couple of things:
In project settings ->General, select your storyboard as the main interface
You also need to delete the following lines from YourAppDelegate.m
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
One of the ways, I overcame this was by the following steps:
1) Start Xcode and choose Empty Application
2) Now Goto the File --> New Application under UI
3) Give it a name --> myView
4) Now create a custom Class --> myView
5) Goto the .xib file now and click on the File Owner and under the Class Attribute enter --> myView as the custom Class
6) Now add a button and create an action
7) It should work
Select your target project.Then set your mainstoryboard name from the dropdownlist in summary section.
Maybe it does sound stupid, but I got this error because I linked the root view controller with one button's event. This issue was gone when I removed this connection.
Swift 2 solution that worked for me :
Insert the code below in AppDelegate -> didFinishLaunchingWithOptions
self.window!.rootViewController = storyboard.instantiateViewControllerWithIdentifier("YourRootViewController") as? YourRootViewControllerClass
This is my storyboard:
I am trying to access tabBarController from a method inside AppDelegate.m
This is AppDelegate.h:
#import <UIKit/UIKit.h>
#import <FacebookSDK/FacebookSDK.h>
#import "STAlertView.h"
#interface demo_AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) STAlertView *av;
#end
And this is AppDelegate.m:
#import "demo_AppDelegate.h"
#import "demo_Friends_ViewController.h"
#implementation demo_AppDelegate
-(void)showFriendReqAlert:(NSNotification *)pNotification{
NSLog(#"Hello from showFriendReqAlert:");
NSLog(#"Root: %#", [self.window.rootViewController.navigationController.tabBarController viewControllers]);
}
....
....
....
....
#end
My main motive is when this method showFriendReqAlert: is called, a red badge is shown to the third tab bar item which is Friends. But whenever i try to select tabBarItem, it says null in NSLog.
I have also tried the following:
self.window.rootViewController.navigationController.tabBarController
self.window.rootViewController.tabBarController
but nothing works. Any help?
Thanks!
I believe (sorry for believing here ;-) that the TabBarController should be your first controller and your navigationBarController must come afterwards as it does not make much sense for the navigationController (if you change a tab) what to push/pop.
I suggest that you remove your first DemoViewController and following NavigationController and that your first Controller is your TabBarController (simply set "Is Initial View Controller" in IB).
Then you can access your tabBar like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UITabBarController *tbc = (UITabBarController *)self.window.rootViewController;
}
Swift 5:
guard let tabBarController = window?.rootViewController as? UITabBarController else { return }
I'm normally just use storyboard for my iOS, but needed to integrate an SDK which does not use storyboard, rather xib. My initial view controller is from storyboard, and when a button is pushed (IBAction), I would like it to go to the xib view controller, but not sure how programmatically to do so. Here is my AppDelegate:
//AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:...{
// set to storyboard on launch
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"iPhoneStoryboard"
bundle: nil];
UIViewController* viewController = [mainStoryboard instantiateInitialViewController];
[self.window setRootViewController:viewController];
[window makeKeyAndVisible];
return YES;
}
Here is my code .h:
//mainVC.h
#import <UIKit/UIKit.h>
#interface MainVC : UIViewController{
UIWindow *window;
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#property (nonatomic, retain) IBOutlet UIButton *buttonScan;
-(IBAction) ActionScan;
#end
And the .m:
//mainVC.m
#interface MainVC ()
#end
#implementation MainVC
#synthesize window;
#synthesize navigationController;
#synthesize buttonScan;
- (IBAction)ActionScan{
window.rootViewController = navigationController;
[window makeKeyAndVisible];
}
create instance of your xib viewController with initWithNibName
MyViewController *controller = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
& then push this controller instance on navigation controller
[self.navigationController pushViewController:desController animated:YES]
In the view controller in storyboard, code below:
alloc & init destination view controller:
UIViewController *desController = [[SomeViewController alloc]init];
show the destination view controller:
[self.navigationController pushViewController:desController animated:YES]
or
[self.navigationController presentViewController:desController animated:YES completion:nil
Usually you don't set the window's rootViewController directly. Instead you should use
- (IBAction)ActionScan{
[self presentViewController:self.navigationController animated:YES completion:nil];
}
to show your next view controller. The first and accepted answer to this question gives a more detailed explanation of how this works.
Changing root view controller of a iOS Window
Setting window.rootViewController and calling [window makeKeyAndVisible] usually happens in your app delegate, but since you're using storyboards, it is done for you under the hood.
Also, unless you're using multiple windows, you can access your UIWindow from anywhere using your app delegate singleton object.
MyAppDelegateClass *appDelegate = (MyAppDelegateClass*)[[UIApplication sharedApplication] delegate];
UIWindow *mainWindow = appDelegate.window;