Creating a view controller without a nib - ios

In AppDelegate, I want to create a UIViewController subclass and add it's view. The viw itself will be specified in code - there is no nib.
Based on the apple docs, I should use
initWithNibName:nil bundle:nil];
and then in loadView of the controller, I add my subviews etc.
However, the follwing test code below does not work for me. I modelled the AppDelegate code on Apple's PageControl demo, simply because my app will implement a similar structure (specifically a base controller to manage a paged scroll view, and an array of other controller's to build the pages).
But I suspect my AppDelegate code is the problem, since logging proves that initWithNibName:: and loadView both fire. The app as below runs, but the screen is blank. I am expecting a green view with a label.
AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
ScrollerController *controller = [[ScrollerController alloc] initWithNibName:nil bundle:nil];
[self.window addSubview:controller.view];
[self.window makeKeyAndVisible];
return YES;
}
ScrollerController (the UIViewController subclass)
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)loadView{
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
UIView *contentView = [[UIView alloc] initWithFrame:applicationFrame];
contentView.backgroundColor = [UIColor greenColor];
self.view = contentView;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(40, 40, 100, 40)];
[label setText:#"Label created in ScrollerController.loadView"];
[self.view addSubview:label];
}

Try to use:
self.window.rootViewController = controller;
instead of
[self.window addSubview:controller.view];
Note, that you should also #synthesize window; and create it
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

Instead of initWithNibNamed:, just use alloc and init or any of the other designated initalizers for the view controller. Here is an example from a project
hoverViewController=[[BDHoverViewController alloc] initWithHoverStatusStyle:BDHoverViewStatusActivityProgressStyle];
self.window.rootViewController=hoverViewController;
[self.window makeKeyAndVisible];
also, the correct form( for now anyways) for adding the root view controller to the window in the app delegate is like this:
self.window.rootViewcontroller=controller;
[self.window makeKeyAndVisible];
You don't need to add the view to the window. The above code does it automatically.
Good luck,
T

Related

UINavigationController: viewDidLoad is called but doesn't affect the UI

I have this in the App Delegate
- (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];
OneViewController *vc = [[OneViewController alloc] initWithNibName:#"OneViewController" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
[self.window setRootViewController:nav];
[self.window makeKeyAndVisible];
return YES;
}
and this in OneViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
[button setTitle:#"Hi" forState:UIControlStateNormal];
[self.view addSubview:button];
}
But when I run the app in the simulator, the OneViewController screen is blank. It has a xib file which is just the default blank xib.
the button's background color and the title's font color both are white by default in iOS 7. can you set the button's background color or button's title color to black to make the button to appear?

Black empty area below table in iOS7 with nested UIViewControllers

I get some black empty area below a UITableViewController when nested in a certain way (iOS7). Would anybody know why that happens?
(obviously the code is a 100% stripped down version of the actual app's code)
- (BOOL) application:(UIApplication *) application didFinishLaunchingWithOptions:(NSDictionary *) launchOptions {
UITabBarController *tabBarController = [UITabBarController new];
UITableViewController *demoViewController = [UITableViewController new];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:demoViewController];
tabBarController.tabBar.translucent = NO;
navigationController.navigationBar.translucent = NO;
// THESE LINES INTRODUCE A BLACK AREA BELOW THE TABLE
InBetweenViewController *inBetweenViewController = [InBetweenViewController new];
[inBetweenViewController addChildViewController:navigationController];
[inBetweenViewController.view addSubview:navigationController.view];
tabBarController.viewControllers = #[ inBetweenViewController ];
// INSTEAD, THIS LINE WORKS CORRECTLY
/* tabBarController.viewControllers = #[ navigationController ]; */
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
#implementation InBetweenViewController
- (void) viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
for (UIView *subview in self.view.subviews) {
subview.frame = self.view.bounds;
}
}
#end
It's because your inBetweenViewController doesn't know how to render its childViewController. You just add the the view of that controller without any further instructions. It should be possible to solve this by using a simple autoresizingMask. You then also need to make sure that the subview's size is the same as the superview's size when you add it. If you need more details on how to do that, let me know.

Adding UIImageView to rootViewController

All I am simply trying to do is display an image on the screen as I am just starting out iOS
development. I figured since UIImageView is a subclass of UIView, I would add it in a similar way but I am not having any luck. I understand this is an easy question but any help would be appreciated.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.rootViewController = [UIViewController new];
UIImage* stallion = [UIImage imageNamed:#"stallion1.png"];
UIImageView* iv = [UIImageView alloc];
iv.image = stallion;
[self.window.rootViewController.view addSubview:iv];
[self.window makeKeyAndVisible];
return YES;
}
Try something like this:
App delegate:
#import "RootViewController.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
//allocate and initialize the root view controller
RootViewController *rootViewController = [[RootViewController alloc] init];
//set the root view controller
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
Create a subclass of UIViewController called RootViewController
.h
#import <UIKit/UIKit.h>
//set the class RootViewController as a subcalss of UIViewController
#interface RootViewController : UIViewController
#end
.m
//this is one of the life cycle methods of a UIViewController and should already be in the code when the class is created
- (void)viewDidLoad
{
//execute the viewDidLoad method of the superclass (UIViewController)
[super viewDidLoad];
//allocate and initialize the image view
//assign the image view a frame
//x offset from the left = 0.0
//y offset from the top = 0.0
//width = the view controller's view's width (should be the whole screen)
//height = the view controller's view's height(should be the whole screen)
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height)];
[iv setImage:[UIImage imageNamed:#"myImageName.png"]];
//the background will be red if everything is setup correctly, but the image isn't found
[iv setBackgroundColor:[UIColor redColor]];
//add the image view to the view controller's view
[self.view addSubview:iv];
}
//EDIT
It would be very helpful for you if u will read book in which there are information about View Controllers. This is very essential information. I recommend you to read "The Core IOS 6 Cookbook" by Erica Sadum. It really helped me.
You can also just look at the apple documentation http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewControllerCatalog/
Write something like this in AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
MyViewController *viewController = [[MyViewController alloc] init];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
return YES;
}
Next you must add the UIImageView but only when the view of the created view controller is loaded. The best method for this is viewDidLoad. You can also use viewDidAppear: or viewWillAppear:.
You must override this methods in MyViewController class (which should inherit from the UIViewController class).
- (void)viewDidLoad
{
[super viewDidLoad];
UIImageView *imageView = [UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.frame.size.width, self.frame.size.heigth);
imageView.image = [UIImage imageNamed#"stallion1.png"];
[self.view addSubview:imageView];
}

initWithFrame is given empty frame

I'm attempting to use a UINavigationController that utilizes a custom subclass of UINavigationBar. However, I'm running into a problem with initWithFrame. When initWithFrame is called, I print out the dimensions and it shows a 0.0 width and 0.0 height. But, when I print out the same frame in -(void) layoutSubviews inside of the UINavigationBar subclass, the frame is correctly set. Why is initWithFrame receiving a zero-sized frame, and what can I do to fix this? It doesn't sound correct to be manually calling initWithFrame or anything like that, since UINavigationController should take care of that. Here is the relevant code:
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UINavigationController *navController = [[UINavigationController alloc] initWithNavigationBarClass:[CustomNavigationBar class] toolbarClass:nil];
CoolViewController *vc = [[CoolViewController alloc] init];
[navController pushViewController:vc animated:YES];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
CustomNavigationBar.m
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
NSLog(#"initWithFrame with frame: %f, %f", frame.size.width, frame.size.height); // This prints "initWithFrame with frame: 0, 0"
}
return self;
}
Thank you!
I believe the navigation controller doesn't actually set the frame size to a specified value. Instead, it asks the navigation bar for its sizeThatFits: and uses that. By definition, that can't be done and passed to initWithFrame:. So, you want to use a combination of sizeThatFits:, setFrame: and layoutSubviews to add, size and reset your navigation bar content.

Programmatically change NIB checkboxes

I'm trying to set my nib properties programmatically. Specifically, I have a view controller which I initialized with a nib, and now I'm trying to programmatically [mapView setMapType:MKMapTypeHybrid] but it never sets it.
My mapView is an IBOutlet MKMapView, and I dragged a Map View into my nib and conected mapView to Map View.
If I set the Type in the Attributes Inspector of the Map View, it works fine. Is there a way to do this programmatically?
I gave up trying to use nibs months ago (shortly after I started with XCode), but it would be really nice to figure this out.
Thanks
MapTabViewController.h
#import <MapKit/MapKit.h>
#interface MapTabViewController : UIViewController <MKMapViewDelegate>
#property (nonatomic, strong) IBOutlet MKMapView *mapView;
MapTabViewController.m
-(id) initWithTabBarAndNibName: (NSString *) nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = MAPTAB_TITLE;
self.tabBarItem.image = [UIImage imageNamed:MAPTAB_ICON];
self.mapView = [[MKMapView alloc] init];
[self.mapView setMapType:MKMapTypeHybrid];
}
return self;
}
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.dataModel = [[DataModel alloc] init];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
tabBarController = [[UITabBarController alloc] init];
vc_tacTab = [[TacTabViewController alloc] initWithTabBarAndNibName:#"TacTabViewController" bundle: nil];
vc_tacTab.dataModel = self.dataModel;
vc_mapTab = [[MapTabViewController alloc] initWithTabBarAndNibName:#"MapTabViewController" bundle:nil];
vc_mapTab.dataModel = self.dataModel;
NSArray *localControllersArray = [[NSArray alloc] initWithObjects:vc_tacTab, vc_mapTab, nil];
tabBarController.viewControllers = localControllersArray;
[self.window addSubview:tabBarController.view];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
self.mapView = [[MKMapView alloc] init];
Here you are destroying the value in your outlet, and replacing it with a new mapview, which will never be displayed.
When loading from the nib, the outlets will be populated with the objects you have linked them to in the nib. Remove this line and you should be fine.
EDIT - Just realised where this code is being executed. The outlet won't be populated yet - you need to set the property in viewDidLoad, not in the overridden initializer - in fact, all of that code would be better placed in viewDidLoad.

Resources