frame of Root ViewController's View when loaded programmatically - objective-c

Im loading a root view controller in landscape mode at launch(no interface builders are used).
In viewDidLoad, I am adding subviews to root view controllers view, like this
- (void)viewDidLoad
{
[super viewDidLoad];
// self.view.
UIView *toolBar=[[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)];
toolBar.backgroundColor=[UIColor darkGrayColor];
[self.view addSubview:toolBar];
//code contiues...
}
but self.view.frame.size.width returns width of portrait mode instead of landscape.
thanks in advance
EDIT:

Implement the -loadView method:
- (void)loadView
{
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
Also normally the parent view controller is responsible for setting the frame size of its children view controllers views. In the case of the root view controller, I believe it takes the size of the UIWindow it's attached to (so if you set the window size in you app delegate, you can just use [[UIView alloc] init] and then set the autoresizing mask in the -loadView method).
You might need to take the status bar into account in the above code, depending on your own code.

may be, portrait orientations are first in your project file (click to project in xcode, info tab in target, unit Supported interface orientations) ? If so, your app can launched in portrait orientation, then send viewDidLoad and rotate to landscape only after this.

When you do not use Interface Builder/xib files and neither create your view manually within loadview, the systems creates one with the maximum dimensions. This is stated in the loadview method documentation:
If the view controller does not have an associated nib file, this
method creates a plain UIView object instead.
This system generated UIView object has a transform property that is not the identiy transformation and thus you are not allowed to rely on the values from the frame property as stated here:
http://developer.apple.com/library/ios/documentation/uikit/reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/instp/UIView/transform
Warning: If this property is not the identity transform, the value of
the frame property is undefined and therefore should be ignored.
So, what should you to instead? I guess the best solution is to use the bounds property of you UIView. This contains the already rotated coordinates.

Related

How to add UIView as a subview on UIViewController in UIStoryboard

Is there any way that I can add uiview as a subview over a view controller using UIStoryboard, using xib's we can do that, but i'm unable do that using storyboard.
My storyboard is not holding any of the uiview as a subview when I drag and drop on it, it was placing under the view controller.
Is there any way that I can add it programmatically on my view controller using storyboard.? I'm stuck please help me out
Am I right, you want to hold UIView in storyboards without view controller or superview ?
You can't do that. You should use XIBs to hold custom views.
It doesn't matter you add it programmatically or via drag and drop, in storyboards you can't hold "isolated" views, every view must have a superview and therefore a UIViewController.
Check apple's guide, make sure you understand UIViewController,UIView,UIStoryboard classes and relations between them. Also this.
Hope it helped.
Yes, you can override UIViewController's loadView method to do it as i have written code below.
Because loadView is the method which is called first of all other viewController's loading methods. So you can set it here.
Hope this will work for you as I have tested it on my code.
- (void)loadView {
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, [UIScreen mainScreen].bounds.size.height)];
self.view.backgroundColor = [UIColor blackColor];
// enter your customization code here
}
write this line in function
-(void) ViewDidLoad:
[self.view addSubView:...];

Change UIViewController self.view frame

I am trying to display a viewController xib view with its view displayed under a fixed header banner (0,0,320,44) which is an imageView added on Application window.
This is because I need it to stick on the screen while I navigate multiple view controllers. Its a requirement of the project I am doing.
So far I have tried:
Resizing the XIB view to the appropriate frame size (0,0,320,416), both with dot notation and setter.
Changing the frame in viewDidLoad with self.view.frame = CGRectMake(0, 44, 320, 416);
but it is not working. Any suggestion?
Set the frame in viewWillAppear
- (void)viewWillAppear:(BOOL)animated
{
self.view.frame = CGRectMake(0, 44, 320, 416);
[super viewWillAppear:animated];
}
Just want to add a bit more. The reason for changing view of a UIViewController does not work in viewDidLoad is because of the call [window makeKeyAndVisible], which is usually called after your viewDidLoad. This call will change the frame of the window.rootViewController to equal the window's frame. You can test this by changing the UIViewController's view.frame AFTER [window makeKeyAndVisible], and the changes will stick.
viewWillAppear and viewDidAppear are called within [window makeKeyAndVisible] but after the view's frame got resized.
The caveat is that only the top most controller which is the rootViewController has its view's frame changed automatically. This DOES NOT affect any childViewControllers attached to the rootViewController.

Create views programmatically

I write a simple ios app. All of my views are created programmatically.
Here is some code
rootViewController.m
-(void)loadView
{
UIView *view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
self.view = view;
self.view.backgroundColor = [UIColor greyColor];
}
In appDelegate I add rootViewController view to the window and everything work fine. But if expression
self.view = view
is removed rootViewController is not loaded in window.
Why is this happening ?
Because if you don't set the view property of the view controller then the view controller's view is nil and a nil view means a blank screen.
What would you expect to happen if you try to display a view controller with a nil view?
Normally view controllers create their own empty view (or load it from a nib file) when you first reference their view property, but since you are overriding the loadView method, you have to set the view yourself.
Your code may be easier to understand if written like this - the view variable and view property having the same name may be the source of your confusion:
-(void)loadView
{
self.view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
self.view.backgroundColor = [UIColor grayColor];
}
Incidentally, if you aren't using ARC, you need to autorelease the UIView above before you assign it to the self.view or you'll have a leak.

Setting size property in UIScrollview

I would like to create a scrollview inside of another view. I put a UIScrollview element in IB and declared a UIScrollview in my view controller file that is associated with the main view. I also declared it a property in the view controller header file and synthesized in the corresponding implementation file.
Do I set the size of the scrollview in the app delegate or in the view controller? If I set it in view controller do I still have to do the allocation and initialization commands for that instance? Or do I rely on the getter and setter methods that exist as a result of the scrollview being a property?
I should add that I only want the scrollview to occupy a part of the main view.
Here's my viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
[scrollView setFrame:CGRectMake(0, 44, 768, 1000)];
[scrollView setContentSize:CGSizeMake(768, 1000)];
// Do any additional setup after loading the view, typically from a nib.
}
The actual size of the UIScrollview in IB is 768 by 804, there should be a vertical scrollbar present (some of the UI elements in the scrollview are clipped, so there should definitely be a scrollbar if this view is set up correctly.)
Yes you can set the frame property of the scrollView instance using setFrame.
i.e. irrespective of what frame size you have defined in IB, using [scrollView setFrame:CGFrameMake()]; you can redefine the exact width, height & x, y coordinates.
In fact this is how one goes about creating a dynamic view in iOS.
Once you are exiting this view entirely make sure you dealloc & release this IB instance since it would have been defines as retain.

Ensuring that a UIViewController is fully set up before loadView is called

There is a UIViewController that uses a UIImageView, and that image view is initialized with image data (NSData). It does not use a XIB, but creates its view programmatically:
- (void)loadView
{
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageWithData:self.imageData]];
scrollView = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
scrollView.contentSize = imageView.bounds.size;
scrollView.delegate = self;
[scrollView addSubview:scrollView];
}
That data has to be set by another controller which allocs, inits, and pushes this view controller onto the navigation controller:
ImageViewController *imageViewController = [ImageViewController alloc] init];
imageViewController.imageData = someData;
[self.navigationController pushViewController:imageViewController animated:YES];
How do I know that everything that needs to be done, which in this case, is setting the data, is done before loadView is called? Or, do I not know, and I have to create a custom initializer, or somehow call loadView again when the view controller receives the data?
I have faced many similar situations where I was confused about what will happen, such as with UITableViewControllers.
How do I know that everything that needs to be done, which in this case, is setting the data, is done before loadView is called?
Because the documentation mentions that view controllers do not load their views until they are needed. And the view controller's view is not needed before the navigation controller tries to push it on screen.
Besides, the proper place for assigning the imageData to your image view is probably viewDidLoad ("If you want to perform any additional initialization of your views, do so in the viewDidLoad method."). And your loadView method will not do anything visible in its current form. You have to assign a view to the view controller's view property in that method.
loadView will happen when the view property of the view controller is accessed. The code you wrote will work fine, because the first time the view property will be accessed will be somewhere inside pushViewController.
If you wrote this you'd have a problem:
ImageViewController *imageViewController = [ImageViewController alloc] init];
NSLog(#"size = (%.0f, %.0f)", imageViewController.view.frame.size.width,
imageViewController.view.frame.size.height);
imageViewController.imageData = someData;
[self.navigationController pushViewController:imageViewController animated:YES];
because you access the view property in the NSLog. That would cause loadView to get called before imageData was set.