views:

75

answers:

2

I am using the iPhone toolchain on Linux and so I have no Interface Builder. So how could I layout my view in my ViewController subclass? For example, I want a UITextView in the middle of the screen? Should I do this in the loadView or viewDidLoad. Do I also have to set the view for the ViewController subclass to itself?

+2  A: 

It is not an easy job to layout all the view using code. Here are some code:

UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake (100, 100, 100, 100)];
[self.view addSubview:textView];

The frame is the place (the first and second argument is x and y coordinator) and the size (the third and fourth argument is width and height of the text view).

Using this way, you can add any view into your class. Some of the view is built in and you don't have to draw yourself, some of them is not, and you need to subclass UIView and override drawRect.

You should do this in viewDidLoad when your main view controller is finished loading

vodkhang
A: 

I usually build the entire view hierarchy in the loadView method and perform additional setup in the viewDidLoad, for example to set up the subviews content to reflect the data associated to the view controller. The important thing is to set the view controller view outlet in the loadView method.

@synthesize label; // @property(nonatomic,retain) UILabel *label declared in the interface.

-(void)loadView {

// Origin's y is 20 to take the status bar into account, height is 460 for the very same reason.
UIView *aView = [[UIView alloc]initWithFrame:CGRectMake(0,20,320,460)];
[aView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
[aView setAutoresizeSubviews:YES];

// The 150x50 label will appear in the middle of the view. 
UILabel *aLabel = [[UILabel alloc]initWithFrame:CGRectMake((320-150)/2,(460-50)/250,150,50)];

// Label will maintain the distance from the bottom and right margin upon rotation.
[aLabel setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin];

// Add the label to the view hiearchy.
[self setLabel:aLabel];
[aView addSubview:aLabel];

// Set aView outlet to be the outlet for this view controller. This is critical.
[self setView:aView];

// Cleanup.
[aLabel release];
[aView release];
}

-(void)viewDidLoad {

// Additional and conditional setup.

// labelText is an istance variable that hold the current text for the label. This way, if you
// change the label text at runtime, you will be able to restore its value if the view has been
// unloaded because of a memory warning.
NSString *text = [self labelText];
[label setText:text];

}

-(void)viewDidUnload {

// The superclass implementation will release the view outlet.
[super viewDidUnload];

// Set the label to nil.
[self setLabel:nil];
}

The biggest difficulty is probably understanding how IB settings map to UIView variables and methods, for example the autoresizing mask. Apple's UIView and UIViewController class references are full of useful informations.

sigsegv
I am not using interface builder, so would the first line of your code sample even be necessary? I know I can omit the IBOutlet. Could I also omit the property declaration and therefor the synthesize declaration?
Mohit Deshpande
It depends. Any element you add as a descendant of the view outlet is retained and released with it, so it is not necessary. However, if I need to access a subview anywhere in the controller, I would rather have it as a convenient instance variable and set it to nil in the viewDidUnload and release it in the dealloc, like the label in the above sample. This way I don't end up with a pointer to a deallocated object. You can also just assign it manually or use a (assign)property, or assign a tag to it and recover it when needed, but setting it as a (retain)property is safer and cleaner imo.
sigsegv