In my app, I do not intend to show the status bar. So, my app covers the whole screen view. I could manage doing it inserting the
- (BOOL) prefersStatusBarHidden{
return YES;
}
method in my main viewController and also adding to my app delegate
if ([self respondsToSelector:#selector(setNeedsStatusBarAppearanceUpdate)]) {
// iOS 7
[self performSelector:#selector(setNeedsStatusBarAppearanceUpdate)];
} else {
// iOS 6
[application setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
}
This all works well when I open the app in the portrait mode. However, when opened in the landscape mode, while the status bar gets hidden, I see a black band of background image on top of my view. Indeed my view is vertically offset by the height of status bar height (see picture below).
This does not happen if I open the app first in portrait mode and then rotate. So, I am doing something wrong in the initialization of the view frame I thought, which I do by the usual
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
[self.view setFrame:screenRect];
Any suggestions on this would be really appreciated.
Thanks in advance,
Nikhil
I seem to have fixed the issue (at least for now). I did not fix in the info-plist the options
I hate this. To do one single setting one has to add so many things, that too in different places: one in the appDelegate, other in the main view controller and yet another completely outside the code :(.
Related
On iPad, I have perfectly working UISplitViewController.
I can hide and show its primaryViewController, and splitViewController:willChangeToDisplayMode: is called in appropriate way.
But on iPhone, something is wrong.
I can show primaryViewController, but cannot hide it, because the primaryViewController appears in full screen size. It's so full that I can't touch the secondary view, in that way I can hide the primaryViewController on iPad.
splitViewController:willChangeToDisplayMode: is not called either.
I have a viewDidLoad below, in my custom UISplitViewController class.
// UISplitViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.delegate = self;
self.preferredPrimaryColumnWidthFraction = .1;
CGRect mainScreen = [[UIScreen mainScreen] bounds];
self.minimumPrimaryColumnWidth = 270;
self.maximumPrimaryColumnWidth = mainScreen.size.width - 5;
}
On iPhone, any of these property seems not to be working: preferredPrimaryColumnWidthFraction or minimum/maximumPrimaryColumnWidth
I am adding this splitViewController as rootViewController in AppDelegate.m by the code below.
// AppDelegate.m
[_splitViewCon addChildViewController: tagNaviCon];
[_splitViewCon addChildViewController: mainNaviCon];
self.window.rootViewController = _splitViewCon;
I searched web and found some keywords like "container view".
Is this something I have to do with, when I want to use a UISplitViewController on iPhone ?
I also watched WWDC Video, but I didn't understand "how to code it exactly".
Currently, I do not use any Interface Builder. So I'd be rather glad if someone gives programmaticaly way to code it.
Thank you !
You can have side-by-side UISplitViewController on iPhones 4S, 5, 5S and 6 as well.
To do it you have to embed its view in another view controller (addChildViewController:...didMoveToParentViewController:)
After that you'll be able to control split's behaviour by overriding its trait collection (setOverrideTraitCollection:forChildViewController:). Basically here you have to inspect your current trait collection and change the horizontal size class to regular. This way the UISplitController will be able to show both master and detail views (primary and secondary now called) by setting split's preferredDisplayMode
Then on rotation you can make the same observations about your trait collection and change the preferredDisplayMode and override again if necessary the split's trait collection. This can be done in viewWillTransitionToSize:withTransitionCoordinator: or willTransitionToTraitCollection:withTransitionCoordinator:. The second one won't be called on an iPad as its size classes are alway regular on both orientations.
One note about a problem I'm still not able to resolve. On iPhone 5S for example when rotating in portrait I'm hiding the master controller so to have only one view on the screen and the UISplitViewController should adapt itself to a UINavigationController. That works fine however during the rotation animation the master view is disappearing and you can see a blank ugly space.
One other note as well.
You have to implement UISplitViewControllerDelegate and use methods in order to set which view controller should be visible on app launch and when split is used as a navigation.
Here is a thread about this.
Hope it helps and if I find solution about the problem I have I'll update my answer
The #user1006806 answer worked for me. Here's how I got rid of the ugly blank space during the rotation from within my UISplitViewController's rotation method (iOS 8):
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
UIInterfaceOrientation theOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if (UIInterfaceOrientationIsPortrait(theOrientation)) {
self.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
} else {
self.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic;
}
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
self.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic;
}];
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
It seems to be a feature on iOS 8 that the status bar is hidden when in landscape mode. One can get the status bar back, which is fine, but I actually have no objection to it being hidden except that the navigation bar in my app has the top few pixels cut off, as you can see in this simulator screenshot:
See how the gear icon is right up against the top of the screen? It should have a little more breathing room than that.
It's better if I restore the status bar, but I wouldn't mind leaving it out if I could get the navigation bar to have a little more space. Studying the Messages app on iOS 8, I see that the nav bar height is the same as what I'm seeing, but the compose button gets smaller. How do I update my app to reduce the size of the navigation bar items in landscape?
Turns out that I had been setting the font size of that settings button (which just has U+2699 (⚙) for its title) in -viewDidLoad:
UIBarButtonItem *settingsButton = self.navigationItem.leftBarButtonItem;
[settingsButton setTitleTextAttributes:#{NSFontAttributeName: [UIFont systemFontOfSize:28]}
forState:UIControlStateNormal
];
That's why it was too big in horizontal orientation on iOS 8, though just right in portrait.
To fix this issue, I deleted this code from -viewDidLoad and added two new methods to handle resizing it:
- (void)setSettingsButtonFontSize:(CGFloat)size {
UIBarButtonItem *settingsButton = self.navigationItem.leftBarButtonItem;
[settingsButton setTitleTextAttributes:#{NSFontAttributeName: [UIFont systemFontOfSize:size]}
forState:UIControlStateNormal
];
}
- (void)setSettingsButtonFontSizeForVerticalSizeClass:(UIUserInterfaceSizeClass)sizeClass {
[self setSettingsButtonFontSize:sizeClass == UIUserInterfaceSizeClassCompact ? 20 : 28];
}
The first method merely sets the specified font size; the second selects a size for based on a size class parameter.
To get it to size properly, I added this code to -viewWillAppear::
if ([self respondsToSelector:#selector(traitCollection)]) {
[self setSettingsButtonFontSizeForVerticalSizeClass:self.traitCollection.verticalSizeClass];
} else {
[self setSettingsButtonFontSize:28];
}
So I get the original behavior on iOS 7, but on iOS 8, the icon gets sized to 20 when the vertical size class is compact.
And finally, I added the new-to-iOS-8 method to handle rotations:
- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
[self setSettingsButtonFontSizeForVerticalSizeClass:newCollection.verticalSizeClass];
}
So now, on iOS 8 on the iPhone, the gear is 20 in landscape orientation and 28 in portrait. And now it looks good in landscape, not too crowded:
You might be adjusting frames in the wrong place. I recommend setting all frames (i.e. the frame of the gears) in the viewDidLayoutSubviews method.
I know this question has been asked several times and the solutions I have seen have been very helpful. But since i have 2 conflicting requirements, I am a little stranded and hoping to find some help.
So here are the requirements:
We have multiple View controllers out of which only one needs to be full screen (without status bar on the top).
The other view controllers need to show a black status bar with a dark gray navigation bar
The First View controller is embedded in a navigation controller.
As recommended in some of the other posts, I did the following
Set UIViewControllerBasedStatusBarAppearance to NO
Added this code in app delegate
CGRect frame = [[UIScreen mainScreen] bounds];
self.window.frame = CGRectMake(0,20,frame.size.width, frame.size.height-20);
self.window.bounds = self.window.frame;
It works fine if I only stay in those View controllers that have the status bar.
The moment I open the FULL screen view controller, that VC is cut off on the top as shown here.
Additionally when I come back to the Main view controller, now thats shifted up as well and the title bar is where the status bar was showing.
I have tried to push the views back down by resetting the view.frame and requesting layout but it doesnt take effect.
Any suggestions on how to resolve this?
Don't change self.window.bounds in app delegate. Instead, in your view controllers try something like this:
-(void)viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES/NO animated:YES];
[self setNeedsStatusBarAppearanceUpdate]; // For showing/hiding status bar
[super viewWillAppear:animated];
}
- (BOOL)prefersStatusBarHidden {
return YES/NO;
}
You will have different frames for the view in ViewDidLoad according to whether status bar and navigation bar are there.
There is UIView, status bar, iOS 7 and iOS 6.
With iOS 6 everything is good: my UIView (transparent, under "Tap to set destination" label) appears right below status bar. Here is the picture:
The problem is with iOS 7. Here:
I expect that UIView will be under status bar, not beneath it.
I have already tried to detect iOS version and if it's 7 or upper change UIView frame programmatically. But my UI with all the constraints made in storyboard... So it did not help. What can I do to resolve this problem?
UPD: maybe I really should make design more capable for iOS7? I'll think about it, and thanks for recommendations!
In your View Controller viewDidLoad, you should add:
if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)) {
[self setEdgesForExtendedLayout:UIRectEdgeNone];
}
If you really really need to do this you can place the map view inside another view that will be the root view of the controller. This root view will be under the status bar in iOS 6 and take full screen in iOS 7. Set black background for the root view.
Add constrains from this root view to the map view and in viewDidLoad: check iOS version. In iOS 7 change top constrain from 0 to the status bar height (or add contain to topLayoutGuide and remove the top constrain).
But again the behavior you see is normal for iOS 7, and trying to make you view under the status bar you make your app look old-fashioned. May be it's time to reconsider you design.
In iOS 7 that's the default behavior of status bar. I guess the easiest solution will be to hide the status bar all together.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
if ([self respondsToSelector:#selector(setNeedsStatusBarAppearanceUpdate)]) {
// iOS 7
[self prefersStatusBarHidden];
[self performSelector:#selector(setNeedsStatusBarAppearanceUpdate)];
} else {
// iOS 6
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
}
}
// Add this Method
- (BOOL)prefersStatusBarHidden
{
return YES;
}
Try many ways, I saw dozens of post. Finally this is the best solution I found.
Proper way to hide status bar on iOS, with animation and resizing root view
So my app has the status bar set to be hidden like this in the AppDelegate. And it works as intended.
[[UIApplication sharedApplication] setStatusBarHidden:YES];
Then I use UIDocumentInteractionController's presentPreviewAnimated like this,etc.:
[self.docInteractionController presentPreviewAnimated:YES];
I observed that the status bar does show up (with battery info etc.) while in this UIDoc's preview mode. But after dismissing the preview and back to the original view, while the status bar is not there but there is a black bar instead. The size is same as the status bar.
Has anyone encountered this behavior and any remedy for this?
I am facing the same issue. Found a quick fix to this issue...set the view's frame back inside viewWillAppear... My code looks something like this...
-(void)viewWillAppear:(BOOL)animated {
... //other settings
self.view.frame = [[UIApplication sharedApplication].keyWindow bounds];
}
Hope it helps! :)