I am experiencing some weird behavior with my iPad app. I usually add a view to my viewController like this:
CGRect bounds = [[UIScreen mainScreen] applicationFrame];
// Add Basic View
UIView *myView = [[UIView alloc] initWithFrame:bounds];
myView.backgroundColor = [UIColor blackColor];
self.view = myView;
[myView release];
On the iPhone this always works like a charm. On my iPad app however, I add a toolbar to this self.view as a subview with the rectangle (0, 0, self.view.frame.width, 100). Sometimes this works out well and the toolbar displays right below the status bar, yet in certain conditions (eg. when the iPad is lying flat on a table and the interface orientation is portrait) my toolbar slides partly below the status bar. Yet as soon as I rotate the device everything is fine again and the toolbar is aligned properly with the status bar.
I have tried some workarounds with adding values a few points to the origin.y property of the toolbar, yet when I do this the toolbar gets an offset to the status bar after rotating the device. I am really confused by this, did anybody else ever experience this problem? If so, how did you fix it?
Thanks a lot!
Related
I tried to add a UITableView programmatically to my view, but setting its parameters as follows doesn't work (the last cell is cropped).
table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 480) style:UITableViewStylePlain];
I tried to replace the height by 460, which works pretty well. But I want to know the exact size of this bar :
Thanks for your help.
You should never hardcode the exact value of the height at any point in your code.
As long as you use default UI components (UINavigationController / UITableView / UICollectionView / etc.) you usually don't need to worry about the status bar height at all. These ViewControllers should layout correctly on any device and any orientation.
If you do have custom layout needs, you should refer to the safeAreaLayoutGuide on UIView, instead of hardcoding a height:
https://developer.apple.com/documentation/uikit/uiview/2891102-safearealayoutguide?language=objc
But to make this answer complete - the size of the status bar is different on different devices and different orientations:
Most devices up to the iPhone X have a 20pt height in portrait & landscape.
(20px, 40px, 60px in #1x, #2x, #3x)
On iPhone X in portrait it's 44pt (so 44px, 88px, 132px accordingly).
In landscape the height is different though.
Your parent view controller will resize it's view to the right size. You can
make your view controller load a subclass of UIView and override -layoutSubviews
insert your subview with the proper starting size ([[ MyViewClass alloc ] initWithFrame:superview.bounds]) and the proper autoresizing mask. It's important when using autoresizing struts & springs that you give your view the proper size to start with.
BTW--another problem with hard coding the status bar height: it's sometimes double-height. (when the user is recording audio, making a phone call, using internet tethering, using navigation, etc.)
This answer is to Rob's question in the comments to the original question:
So if I don't hard-code my screen size, how can I set it automatically to fit my UIViewController?
Try this:
- (void)viewDidLoad {
[super viewDidLoad];
table = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
// all other table setup
table.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:table];
}
This assumes you want the table view to fill the view controller's view. Adjust as needed.
This will ensure the table view's size changes as the view controller's view size changes. This covers rotations, in-call status bars, etc.
You should't use set pixel dimensions to size something to the screen. use you view's frame. i.e.
table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStylePlain];
Anyway. It's 20 points. 20px non retina. 40px retina.
Update for iPhone X
Previously all iPhone devices have a status bar height of 20pt. But on iPhone X, it's 44pt. So be careful when implementing your UI.
For an iphone project with an "unique" design (with which i am not happy at all) I need to draw a custom view which partially overlaps the navigation bar of a controller in a UINavigationController. Target is iphone/ios 6 with a fixed device orientation (portrait).
My currents solution is to disable the navigation bar programatically via self.navigationController.navigationBar.hidden = YES; in viewDidLoad of my controller and to draw a "fake" navigation bar and paint over this.
This leads to the problem that the status bar color remains black (since there is no real navigation bar visible).
Ios 6 status bar color is discussed here: Status bar color in iOS 6?
I already tried to use [self.view insertSubview:OVERLAPVIEW aboveSubView:self.navigationController.navigationBar] but it did not work and OVERLAPVIEW was drawn beneath the navigation bar.
Is there another way to overlap the navigation bar with another view (z-wise)?
Or is there a way to change the status bar color when no navigation bar is shown (unfortunately in addition to this the view with the overlap is the main view of the app and the first screen visible to the user)
Full disclosure: I am an ios noob and stack overflow lurker - this is my first question on stack overflow, please help me to clarify my question and improve my stack overflow skills if necessary.
Use
[self.navigationController.view addSubview:OVERLAPVIEW];
instead of
[self.view insertSubview:OVERLAPVIEW aboveSubView:self.navigationController.navigationBar];
You can adjust the frame of your view according to make navigation bar partially visible.
I solved this issue by hiding the Navigation bar with
self.navigationController.navigationBar.hidden = YES;
and by adding a navigation bar to my view. Everything added after this new navigation bar will to overlap it (you could use index [parentView.subviews objectAtIndex:0]; as well).
The color of the status bar changes as needed.
In the case of the splash screen i do exactly the same and overlap the navigation bar with the fullscreen splash image.
-(void)viewDidLoad{
[super viewDidLoad];
UINavigationBar * navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 320, 49)];
UINavigationItem *item = [[UINavigationItem alloc] initWithTitle:#"SPLASH"];
[navigationBar pushNavigationItem:item animated:NO];
[self.view addSubview:navigationBar];
CGRect frame = [[UIScreen mainScreen] bounds];
frame.origin.y -= 20;
UIImageView *splashImage = [[UIImageView alloc] initWithFrame:frame];
splashImage.image = [UIImage imageNamed:#"splash"];
[self.view addSubview:splashImage];
}
It seems that this answer solves my issue
Add UIView Above All Other Views, Including StatusBar
Note: at the moment i am not going down this road and I will accept this answer once I tried it (I postponed solving this problem at the moment and it might take a while)
I have an application with 3 view controllers. They are all have shouldAutoRotateToInterfaceOrientation returning YES. The first two, my main menu and my submenu both autorotate just fine. The third viewcontroller, which programatically loads a UIImageView from a jpg file in the program's bundle, will only display in portrait.
In the viewcontroller containing the image, i have this:
NSString *imageName = [NSString stringWithFormat:#"%#-00%d.jpg",setPrefix,imageNumber];
UIImageView *pictureView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
pictureView.frame = CGRectMake(0, 0, 1024, 768);
[self.view addSubview:pictureView];
and again, I have shouldAutoRotateToInterfaceOrientation returning YES for all orientations.
My image shows up, but is sideways, and the 0,0,1024,768 values I used to make my rectangle start from the top right corner going down, instead of starting at the top left and going across (holding in landscape). Am I missing a parameter I need to set in order to ensure the imageview shows up in landscape instead of portrait?
I don't know for sure, but I suspect the setting of pictureView.frame may not be correct. The frame can be "weird" (technical term) when adding a subview to an autorotated view. See Automatically Sizing UIView after Adding to Window.
Im using a typical situation with UINavigationController, id like to make the navigation bar a bit taller. setting its bounds and frame dont seem to make a difference, im using this code
//set up the navigation
UINavigationController *navigationController = [UINavigationController new];
[navigationController.navigationBar setBarStyle:UIBarStyleBlack];
[navigationController.navigationBar setTintColor:[UIColor purpleColor]];
[navigationController.navigationBar setBounds:CGRectMake(0.0, 0.0, 480.0, 100.0)];
[navigationController.navigationBar setFrame:CGRectMake(0.0, 0.0, 480.0, 100.0)];
but to no avail. any ideas?
I don't think you can change the height of a navigation bar. Except when you add a prompt message... But that's not what you want.
Frame is the visible area of a view. Bounds is the internal area. Usually this has an origin of (0, 0) and is as wide and high as the frame. However, when the content exceeds the visible area (like with a UIScrollView) the bounds can be larger (and the origin different). You rarely see bounds that are smaller than their respective frames.
EDIT: Looking at your code, what is [UINavigationController new] about? You should do [[UINavigationController alloc] init], shouldn't you?
Also, what you are doing is not really subclassing...
At the time of 2009, there is probably no way to change the height of UINavigationController. However, in iOS SDK 4.3, there is a way (hack).
To change the height of UINavigationController, change its frame size in viewWillAppear:animated: function. Then, the height will stay customized throughout whole app.
As far as I know the standard navigation bar height should not be changed.
"Specifically, it is alright to
modify the barStyle, tintColor, and translucent properties, but you
must never directly change UIView-level properties such as the frame,
bounds, alpha, or hidden properties directly."
If you like to customize the appearance of navigation bar you can use the appearance proxy [UINavigationBar appearance] in iOS 5
I've been looking for background information on resizing, but I haven't been able to find much. I know I need to set autoresizesSubviews on the superview and autoresizingMask on the subview.
I have done this, and my UIImageViews properly resize, but my custom UIView subclass does not.
The code for the UIImageView:
UIImageView *newX = [[[UIImageView alloc] initWithImage:dot] autorelease];
[newX setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[newX setFrame:CGRectMake(0, 0, self.view.bounds.size.width, 1)];
[self.view addSubview:newX];
The code for the custom UIView subclass:
trace = [[TraceView alloc] initWithFrame:self.view.bounds];
[trace setAutoresizingMask:(UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin)];
[self.view addSubview:trace];
From what I can tell, the view rotates as expected, but does not resize. I can no longer see the bottom of it, and it doesn't fill the screen to the right.
Do I have to add anything to the UIView subclass to make resizing work properly?
EDIT:
I've changed the autoresizingMake to (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight) and called [subview setNeedsDisplay]; I'm not sure why this is necessary as the UIImageViews work fine without it, but it now behaves as expected.
I think you're missing UIViewAutoresizingFlexibleHeight or width on the subview. Otherwise I think the view just moves around according to the margins but doesn't resize.
You mention rotation. Is the superview that contains your custom view actually resizing correctly? If in doubt, set its background to some odd color. If it did not resize correctly after the orientation change then you should see a white or grey bar on the right.