I've been adding support for rotation for an app recently and it has been a pain. One thing I'm finding that's fairly consistently annoying is that one of my views shifts up by about 50 pixels or so everytime I rotate between my landscape and portrait mode.
My landscape mode is not actually the same view controller; I push a viewcontroller when I rotate. However, when I rotate back, I have to reset the portrait's view.bounds or else my view ends up shifting upwards.
So in my rotation code, I have to do this:
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
UIInterfaceOrientation toOrientation = self.interfaceOrientation;
if ( self.tabBarController.view.subviews.count >= 2 )
{
if(toOrientation == UIInterfaceOrientationPortrait)
{
self.tabBarController.tabBar.hidden = NO;
self.navigationController.navigationBar.hidden = NO;
CGFloat height = [[UIScreen mainScreen] bounds].size.height;
CGFloat width = [[UIScreen mainScreen] bounds].size.width;
self.view.bounds = CGRectMake(0, -55, width, height);
}
}
}
Surely this can't be right. In my app, there is a navbar and the standard status bar (batt life, reception, etc) occupying the top of my app. But...it seems like my view is slipping too upwards unless I set the y coordinate origin to be negative (which makes no sense!).
What's happening?
In my app, I hide the tabbar and navbar when I go to landscape mode. The statements to make the bars hidden are written into the portrait view's viewcontroller's code.
When I transition back from landscape mode to portrait mode, the landscape viewcontroller gets popped and I get the weird shifted views. Turns out this was caused by the order in which the tab/nav bar un-hiding statements.
My tab/nav bar un-hiding statements were in the portrait viewcontroller, so they were called too late. After moving the tab/nav un-hiding statements to the rotation code in the landscape viewcontroller (rather than the portrait's viewcontroller), my problem disappeared.
Related
I need to add the ads functionality in my iOS App. And ads screen would appear after some time interval. My whole is in Landscape mode only. When I tried to add the view on current view then it shows the views in portrait mode not in landscape mode. I have set the view frame i.e. CGSizeMake(0,0, 568, 320)
time = [NSTimer scheduledTimerWithTimeInterval:2.0f
target:self
selector:#selector(showfirstad)
userInfo:nil
repeats:YES];
-(void)showfirstad {
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:firstad];
}
It appears like this .
_window = [UIApplication sharedApplication].keyWindow;
if (!_window) _window = [[UIApplication sharedApplication].windows objectAtIndex:0];
UIInterfaceOrientation orientation = self.window.rootViewController.interfaceOrientation;
// Set appropriate view frame (it won't be autosized by addSubview:)
CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
if (UIInterfaceOrientationIsLandscape(orientation))
{
// Need to flip the X-Y coordinates for landscape
self.view_login.frame = CGRectMake(appFrame.origin.y, appFrame.origin.x, appFrame.size.height, appFrame.size.width+20);
else
{
self.view_login.frame = appFrame;
}
[[[_window subviews] objectAtIndex:0] addSubview:self.view_login];
The reason your UIView gets displayed in portrait orientation while the rest of your app gets displayed in landscape is because you are adding the UIView as a subview of your window rather than adding it as a subview of a view controller's view. This places it outside of the view hierarchy that gets transformed automatically through autorotation.
The app's window object coordinates autorotation by finding its topmost subview that has a corresponding view controller. Upon device rotation, the window calls shouldAutorotateToInterfaceOrientation: on this view controller and transforms its view as appropriate. If you want your view to autorotate, it must be a part of this view's hierarchy.
So instead of [window addSubview:UIView];, do something like [self.view addSubview:UIView];
I had the same issues with rotation and autolayots when used addSubview:myView.
I managed to solve this problem by using standard container controllers or placing views directly to storyboard.
You can probably just add the view that will keep your ad into the screen in storyboard and then set hidden property to YES. Then you can change it to YES after some time.
I have one specific viewcontroller which I wish to behave that way:
When loading, if device is landscaped, show landscape but no auto rotation.
When loading, if device is Portrait, show portrait but no auto rotation.
I cannot find the right solution for that, can any one advise?
Try checking the orietation on viewWillAppear() and then set views to show on the way you want according to the orientetation.
int orientationType = [[UIDevice currentDevice] orientation];
1 = Portrait 2 = Portrait (Upside down) 3 = landscape (Right) 4 = landscape (Left)
To disable auto rotate on a view just:
- (BOOL) shouldAutorotate {
return NO;
}
I have a weird behaviour with my view representation.
my structure:
Window -> MyTabbarController -> GraphViewController -> (modal) SelectItemViewController;
settings of Window:
After I updated my app to the retina 4 resolution (and set the UIWindow size in the Window.xib to Retina 4 fullscreen), the origin of myTabbarController was set to 0,88 in the Retina 3.5 devices (in retina 4 there are no problems).
If I use non-modal controllers, I can rotate till end of days, everything works fine.
But if I call the modal view in UIInterfaceOrientationLandscapeLeft (for UIInterfaceOrientationLandscapeRight works everything fine) or dismiss the modalView in same state, the parentView of GraphViewController (MyTabbarController) gets a wrong frame...
CALL the modal view:
DISMISS the modal view
I am thankfull for every help.
ps: setting the UIWindow size to Retina 3.5 fullscreen or freeform makes it looking wrong in iPhone 5. Also setting the modalPresentationStyle doesn't do anything :/
Problem was solved by setting the window size in code:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
window.frame = [UIScreen mainScreen].bounds;
window.rootViewController = tabBarController;
...
after setting this, the frame was always set on the correct position.
I think it was just a problem of the binding of the view to the window and it's orientation in this "container" (screen has a 'width' of 480 but frame 568 pixel in landscape mode. And the gray part was just this difference (88 pixel) to the right (non-bounded) side of the modal view)
I added a webview to a UIViewController. I assumed that I could match it's size to the UIViewController's view, but soon realised that the UIControllerView frame was independent of the screen orientation, and so displayed the frame as it would be in portrait mode (so the wrong way around, if the screen was in landscape). Doing UIInterfaceOrientationIsPortrait() doesn't work, because if the device is lying flat then it still reports it as being in portrait, even if the screen is rotated to landscape.
To get around this problem, i checked the orientation of the status bar and then used the UIScreen bounds (also independent of rotation) to work out the current frame, and then removed the size of the status bar, if it's visible.
CGRect frame = [UIScreen mainScreen].bounds;
BOOL isPortrait;
UIDeviceOrientation orientation = (UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown) {
isPortrait = YES;
}
else {
isPortrait = NO;
}
if (!isPortrait) {
frame = CGRectMake(frame.origin.x, frame.origin.y, frame.size.height, frame.size.width);
}
if ([UIApplication sharedApplication].statusBarHidden) {
return frame;
}
else {
return CGRectMake(frame.origin.x,
frame.origin.y,
frame.size.width,
frame.size.height - 20);
}
Now I've run into another problem - even though I set up my UIWebView for autoresizing, the UIViewController's view's frame is independent of rotation, so it doesn't change, therefore my UIWebView doesn't change frame correctly upon rotation.
(Oddly, despite the UIViewController view frame not changing, the view does actually resize itself correctly)
I've tried using the method didRotateFromInterfaceOrientation:, which did resize it, but only after all the rotation animation was done.
Using willRotateToInterfaceOrientation:duration: poses the same problem as earlier - that UIInterfaceOrientationIsPortrait() isn't a true reflection of the orientation.
Anybody managed to do this?
try autoresizing both webview and viewcontroller's view. or you can also take another view and delete default view in nib file of viewcontroller. Autoresize that view and connect to view outlet.
I have created a subview which is used as a HUD in an iOS app. The app supports portrait and landscape display orientations.
The subview appears in portrait mode sometimes even if the mode is landscape. The subview is added by these lines:
self.infoHUDViewController = [[[InfoHUDViewController alloc] initWithNibName:#"InfoHUD" bundle:nil] autorelease];
[self.view addSubview:self.infoHUDViewController.view];
So it works very well if the subview is added in the viewDidLoad method. However, it does not work in landscape mode if the view is added in an IBAction method which responds to a button press. The subview appears as if in portrait mode (it appears 90° rotated, fills only the half screen width, and extends beyond the screen bounds).
What is really odd: In the init method of the subview's view controller the display orientation is correctly set to landscape. Am I missing something here?
I found a fix for this problem.
I added
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
self.view.frame = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
} else {
self.view.frame = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
}
to the viewDidLoad method. Now everything works as excepted in all situations.