I'm trying to understand how the view associated to a UITabBarController, UINavigationController or UIViewController reacts when the in-call status bar is toggled.
My trouble is that they seem to behave differently and this causes me side effects.
I've made a project that changes the root view controller of the window for the 3 types above and I dump the description of the view to get the frame coordinates.
UIViewController
inCall status OFF:
UIView: 0x4e2a1f0; frame = (0 20; 320 460); autoresize = W+H; ....
ON
UIView: 0x4e2a1f0; frame = (0 40; 320 440); autoresize = W+H; ...
This one I understand : when the in-call status bar appears, the height of the view of the UIViewController shrinks and looses 20, and its y coord moves from 20 to 40.
That's perfect ! I would expect the same when replacing a classic UIViewController with a UITabBarController or a UINavigationController but that's not the case !
UINavigationController
InCall status bar OFF
UILayoutContainerView: 0x4b35ab0; frame = (0 0; 320 480); autoresize = W+H; ..
ON
UILayoutContainerView: 0x4e1b060; frame = (0 0; 320 480); autoresize = W+H; ..
In that case, the view handled by the UINavigationController does not have its frame properties changed when the in-call status bar is toggled?! (why ? :( )
UITabBarController
OFF
UIView: 0x4b2f6a0; frame = (0 20; 320 460); autoresize = W+H; ...
ON
UIView: 0x4b2f6a0; frame = (0 20; 320 460); autoresize = W+H; ...
Same as in the UINavigationController: the view of the UITabBarController does not seem to be impacted when the incall status bar is toggled.
Can someone explain me how this resize works when displaying the incall status bar appears ?
My end goal is to display a UIView that is shown ABOVE the whole UITabBarController and that resizes properly when the in call status is displayed. However, I really don't know where to put such a view in the views hierarchy : if I add it as a child of the UITabBarController's view, as this one does not react to the incall status display, mine does not react as well :(
The height of the view when the In-call status bar is toggled depends on the way it's anchored.
Play around with the autoResizingMask of the UIView to control whether the view should move down or resize when the in-call status bar shows up.
These two properties,
UIViewAutoresizingFlexibleTopMargin
UIViewAutoresizingFlexibleHeight
will help you. The first one pushes the view down, the second one changes the size.
Your regular UIViewController example has [wantsFullScreenLayout] set to NO, which causes the view to be automatically sized so it doesn't go under the status bar.
UINavigationController and UITabBarController, on the other hand, default wantsFullScreenLayout to YES. So their views take up the whole window, and they size and position their subviews themselves to appropriately handle the status bar. If you explicitly set the property on these controllers to NO, you should get the behavior you desire (but will then lose the ability to properly handle child controllers that set wantsFullScreenLayout to YES, if you care about that).
In your UITabBarController example, BTW, it seems that you are not printing the information for the view of the tab bar controller; here that is a UILayoutContainerView, not a plain UIView.
Ideally you should forget about how much amount the view gets resized and play around with Autoresizing mask.
Related
I want the view of my current UIViewController to take the whole screen (without the status bar) when I hide the UINavigationBar. It doesn't have to be animated. I can't figure out how to change the frames. I should mention also that I am using a nib, so in the Interface Builder I have selected Simulated Metrics : Navigation Bar, I don't know if it makes any difference.
Try this:
// On YourViewController.m
// Call this method when the nav bar gets hidden
- (void)navigationBarDidBecomeHidden {
self.view.frame = CGRectMake(0, 0, 320, 480);
}
Using storyboard ,I created a project.
Inside viewDidLoad,I did :
NSLog(#"%#",self.view.description);
I got :
<UIView: 0x8789cb0; frame = (0 20; 320 460); autoresize = RM+BM; layer = <CALayer: 0x8789d50>>
But inside another XXControllerDelegate Method , I got :
<UIView: 0x8789cb0; frame = (0 0; 320 416); autoresize = RM+BM; layer = <CALayer: 0x8789d50>>
I found the fact if I didn't choose Resize View From NIB
I always got :
frame = (0 0; 320 416)
But I couldn't find anywhere resize the view from NIB.Who moved my view ?
Your view has RM+BM these anchors will be able to move the view y and x position in regarding to the parent view, when viewDidLoad is called the superview gets its size from the xib file, when viewWillAppear is getting called, the view will resize to the superview
If you want your view to not resize you should remove the RM+BM, check the screen shot
Remove the red horizontal and vertical lines in the right middle part of the image bellow
The frame of an UIView are relative to the superview it is contained within.
The bounds of an UIView are relative to its own coordinate system.
So you need to be sure where you are adding your view.
I have a view that I'm creating in the loadview like this:
- (void)loadView {
UIView *mainView = [[UIView alloc] initWithFrame:[UIApplication sharedApplication].keyWindow.bounds];
self.view = mainView;
[mainView release];
}
So, if I print the view I got the result:
>
OK, that's what I wanted, 767x1024
The problem is, if I call this method:
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
and present a modalViewController and then dismiss it, on my previous view controller, printing the method viewDidAppear and viewWillAppear I got this:
viewWillAppear:
[<UIView: 0x4e946a0; frame = (0 0; 768 1024); layer = <CALayer: 0x4e946d0>>]
viewDidAppear:
[<UIView: 0x4e946a0; frame = (0 0; 768 1004); layer = <CALayer: 0x4e946d0>>]
Why the view size is changing by 20? I know that has something to do with the status bar, but can't figure it out.
Thanks.
You are right. Status bar default size is 20 pixel in height. UIViewController automatically adjust child view size as status bar appears. According to apple documentation "When a view controller is displayed on screen, its root view is typically resized to fit the available space, which can vary depending on the window’s current orientation and the presence of other interface elements such as the status bar." — http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
I have a child view controller that needs to be always shown in landscape mode regardless of which mode the parent view is in. I'm adding it onto the parent's view stack with
[[self navigationController] pushViewController:controller animated:NO];
I am trying to force the view to rotate and be displayed as if the device is held in Landscape orientation even though it's still held in Portrait orientation.
The only problem is that no matter what size and coordinates I set the view frame to, I see a 20 pixel gap on the right side of the screen where the StatusBar used to be during Portrait Mode.
What can I adjust to ensure that this gap is gone?
Here's how I'm doing the transformation (as recommended by this SO article)
- (void)changeOrientationToLandscape
{
UIApplication *myApp = [UIApplication sharedApplication];
CGAffineTransform landscapeTransform = CGAffineTransformMakeRotation( degreesToRadian(90) );
landscapeTransform = CGAffineTransformTranslate(landscapeTransform, +90.0, +90.0 );
[self.view setTransform:landscapeTransform];
// Change the status bar orientation so it's shown as if we're in landscape
myApp.statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
// Manually force view frame - this doesn't seem to fix the 20 pixel gap
self.view.frame = CGRectMake(0, 0, 480, 320);
}
The only time I see the view taking up the entire screen and without the 20 pixel gap is if I hide the status bar all together, something I cannot do for this app.
Here's how the screen looks (it's held in Portrait orientation with the home button on the bottom). Notice how the status bar ends doesn't have the same purple background - I was hoping I could shift the view over so the white gap is no longer present.
I also printed out the view and navigationController's view frames and they both report
x and y location at 0,0. The navigation view frame's reported dimension is 320x480 while view's frame is 480x320.
What about disabling the status bar when child is pushed and enabling when it's "popped"?
You can hide status bar for your child view controller only.
If you're pushing your child view controller via self.navigationController, simply override shouldAutorotateToInterfaceOrientation in child view controller and put this ...
return UIInterfaceOrientationIsLandscape( interfaceOrientation );
... to body of this method to make it landscape only.
I have a scrollview that I had to the view of the view controller pushed to a UINavigationController.
My navigation bar is opaque.
However, the scrollview seems to keep size of the whole parent view. I would like the scrollview to have the size of the space between the toolbar and the navigationbar.
Is this possible or do I have to hardcode some size values?
Thanks in advance
When you initialize your scrollView you can set its contentSize parameter:
[scrollView setContentSize:CGSizeMake(320,392)];
The height of the screen (480) minus the toolbar (44) and navigation bar (44) = 392. Drop that to 372 if you're also displaying the carrier status bar.
or, use the frame geometry properties:
[scrollView setContentSize:CGSizeMake((scrollView.superview.frame.size.width),
(scrollView.superview.frame.size.height -
toolbar.frame.size.height -
navigationController.navigationBar.frame.height))];
When you use autosize, the correct frame size is not known on viewDidLoad.
You should pack this inside viewWillAppear and then everything works fine
scrollView.contentSize = CGSizeMake(scrollView.superview.frame.size.width, scrollView.superview.frame.size.height);