"Incorrect" frame / window size after re-orientation in iPhone - iphone

In my iPhone OS application I want (need) to watch for changes in the device orientation in order to rearrange certain portions of the screen. The approach I used was to use CGRect frame = [UIScreen mainScreen].applicationFrame to get the screen size, and from there calculate the size and / or positioning of other controls (I also tried self.view.frame).
All testing was done so far in Portrait mode, so I could focus on programming the main features and later on just do some adjustments for Landscape. And here enters the problem: In -(void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation I added some logging to check the sizes before proceeding, but apparently the values for Width and Height are "wrong" (I say "wrong" because at a first glance the values does not make sense to me).
Here's the output of some logging:
Rotation: Landscape [w=300.000000, h=480.000000]
Rotation: Portrait [w=320.000000, h=460.000000]
The values for "w" and "h" in Landscape seem inverted to me - I was expecting that w=480 and h=300.
What am I doing wrong? The code I used to debug is below.
-(void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
CGRect frame = [UIScreen mainScreen].applicationFrame;
CGSize size = frame.size;
NSLog(#"%#", [NSString stringWithFormat:#"Rotation: %s [w=%f, h=%f]",
UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? "Portrait" : "Landscape",
size.width, size.height]);
}

The orientation of your device changed, not the physical characteristics of the screen. You basically tipped it on its side, but in reality it is 320 pixels wide (20 of which are not available to you at the moment since the status bar is showing) and 480 pixels tall. If your view is auto-rotating, then the width/height have been translated for you, but when you ask for the actual dimensions of the screen, you get back the actual dimensions of the screen.
This is also why, when working with translated views, it is important to do calculations based on the view's center and the view's bounds and never on the view's frame.

Use self.view.bounds instead.

I've been stumbling over the same problem and with some diagnostic work I discovered that the view's bounds and frame do not accurately reflect the landscape orientation in viewDidLoad (when the device is held in landscape when the view controller is pushed onto the stack), but do so correctly in viewWillAppear: and viewDidAppear:. I just moved my code that needed the dimensions of the frame/bounds from viewDidLoad to viewWillAppear:, and it worked properly.

Related

self.view.bounds in iOS 8 after rotation to portrait mode

In my app, I am dynamically using self.view.bounds to position subviews and I am not using Autolayout. When the view is rotated to portrait mode on iOS 8, I see self.view.bounds to be {568, 320} after view appears as opposed to natural behavior of {320,568} on iOS 7. How do I get this right ?
EDIT : I forgot to mention where I am doing this. This happens in viewDidAppear:. The value of self.view.bounds is incidentally correct in viewWillAppear but somehow it gets screwed up in viewDidAppear:.
EDIT 2: Here is I found on further drilling. Following is the scenario unique to my code :
a. Auto rotation is BLOCKED by me in code by returning only landscape orientation when the view is starting (this has to do with the camera & opengl setup I am doing and I do not want to autorotate the interface till everything is setup,
b.The view is freeform in XIB and has flexible width, height and all the edges in autoresizing mask.
c. Based on the above resize mask, iOS 7 gives self.view.bounds size equal to {320, 568} even though auto rotation has not happened. iOS 8 somehow ignores the same resize mask & the bounds is still {568,320}
So the root of the problem is UIWindow is autorotating in iOS 8 with the device while View controller is denying to autorotate.
In iOS 8, the rectangle returned by [[UIScreen mainScreen] bounds] takes into account the rotation of the device. No longer will the portrait frame be returned when the device is in landscape.
The updated-for-iOS-8 docs for UIScreen -bounds state:
This rectangle is specified in the current coordinate space, which takes into account any interface rotations in effect for the device. Therefore, the value of this property may change when the device rotates between portrait and landscape orientations.
Prior to iOS 8, the discussion section simply said:
Contains the bounding rectangle of the screen, measured in points. (read-only)

iPhone iOS large UIView gets clipped to 320x460 when displayed. How to prevent?

I have a 850x1100 UIView defined in a storyboard it is 4 times the size of a normal window, and I'm using it as a PDF generation template.
The view is wrapped within a scrollview. Yet when I display the view, its frame gets resized and becomes 320x460, effectively cutting off everything outside the frame.
Does anyone have insight on why my UIView defined in a storyboard as 850x1100 gets its frame reset to 320x460 when displayed on an iPhone?
This frame recalculation is not a bug. The frame of a view represents its position and size relative to the screen coordinates.
The iPhone viewing area is 320x480 and any view that has its frame set to a CGRect larger than the viewing area of the device will become "clipped" and have its frame set back to the viewing area (320x460 viewing area due to the status bar).
Try:
scrollView.contentSize = CGSizeMake(850,1100);
scrollView.clipsToBounds = NO;
pdfView.clipsToBounds = NO;
Are you sure it's not the scrollview whose contentsize is too small? It won't automatically resize based on the content - you have to explicitly set the contentSize of the UIScrollView

What is the correct way to get screen width/height with orientation changes?

I'm currently using [[UIScreen mainScreen] bounds].size.width and height to get the screen width and height for getting a new image (that fills the screen) from a server. My problem is it appears that the bounds doesn't change on orientation changes. So if I rotate the device then it still gives me portrait width/heights even though the device is now in landscape. I'd like to not hardcode a screen width/height based on the current orientation. Is there a way that I can check the screen width and height that will correctly reflect orientation changes?
You can get the width and height by
int h = self.view.frame.size.height;
int w = self.view.frame.size.width;
Best way to do this is probably:
CGSize appSize = [UIApplication sharedApplication].keyWindow.rootViewController.view.bounds.size;
and also use appSize.height for height and appSize.width for width
This returns the orientation adjusted size of the topmost view which always fills the full screen, except possibly excluding the status bar depending on your status bar and wantsFullscreen settings.
[UIScreen mainScreen].bounds.size returns the bounds unrotated. You can use the convertRect:fromView: method (passing nil for the fromView) on an appropriate on-screen UIView to adjust for rotation and such.
I've been working on an app where we have run into problems like this on a few occasions, so I hope I can help:
First off, make sure you are using a UIViewController to manage your image.
Secondly, make sure your implementation of -shouldAutorotateToInterfaceOrientation: on that view controller returns YES.
Make sure you are using a UIImageView, not a UIImage for your picture, then try setting autoresizesSubviews on the image view's superview (this is the view controller's view) to YES.
If the image resizes, but not to your liking, try messing with the image view's autoresizingMask.
If, after step 3, the image doesn't autoresize, try implementing willRotateToInterfaceOrientation:duration: and programmatically setting the image's frame. Remember that it's superview (the UIViewController's view) hasn't rotated yet, so its frame hasn't updated.
Finally, if that doesn't work, try willAnimateRotationToInterfaceOrientation:duration:, though I'm not quite clear on the difference between this method and the former.
Hope this helps, and let me know your results!
-Bruce
try get your height and width from applicationFrame
UIScreen.mainScreen().applicationFrame.size.height

trouble with rotating view (and resizing elements within) in ipad application

I'm having a nightmare with the rotation on iPad. I've searched all over the place for some tutorials, but nothing seems to really be for what I want. (Possibly not searching for the right thing?!)
I have a portrait view by default which is an image and a button inside the view. When I rotate, I detect this can work out if it's landscape. I then try to set the frame size of the uiview to fit nicely on the screen.
If I let it autoresize, it simply stretches and fills the screen. This I don't want.
but the trouble is, when I resize, the button gets resized too, but not in the same ratio as the image.
My question is: What's the best way to resize the view. I wanted to simply reduce the uiview by say 60% and it resizes EVERYTHING in that view with the same 60%. The only way I see this is working at the moment is to create two views... but that's twice the work and maintenance!
I've tried messing with the autosizing arrows in Interface builder, but that again seems to screw things up more!
I'm completely lost here!! Thanks for any info
The problem you have there is that the view is automatically resized to the screen ratio. On an iPad in Portrait Orientation the screen size is 1024x768. After the rotation to Landscape the origin rotates too and your screen content is skewed or stretched to 768x1024.
What you need to do is to override the
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
message of the UIViewController of the view which rotates. This message is called within the animation block of the rotation. You just set the framesize of your subviews (the button) to whatever is best for you. Once i had a problem with rotating an OpenGL view. The content of the view was stretched when rotating to landscape. Since it is not possible to alter any OpenGL matrices within the animation block the only solution i found was to make the view quadratic and to set the origin behind the bounds of the screen (in -x direction). You have to override the message also to reset the origin above the screen (in -y direction) bounds in landscape mode, to keep the viewport in the middle of the screen. That way the view kept its ratio. Whatever solution is best for you, overriding this message should work out.
Have you tried disabling the autoresizesSubviews property on your UIView? It should prevent any size changes on the subviews when you resize your view.

UIView parent window's frame and bound dimensions while rotating iPad

I a have a following line of code invoked after a touch gesture has completed:
CGRect parentBounds = self.view.bounds;
CGRect parentFrame = self.view.frame;
when iPad is placed in a vertical way both parentFrame and parentBounds have similar dimensions of w:768 h:1004 (or something close to that), but when I rotate parentBounds is 1024x748 while parentFrame is 768x1024.
Is this behavior normal? I thought I understood the concepts beetwen frames and bounds (and how they relate to each other)... but now I am really confused.
Could anyone explain what is happening with frame and bounds of a window (superview) when rotation occurs?
The window does not change orientation; the root view does. It does this by applying a view transform (self.view.transform). You're not supposed to call frame if transform is not CGAffineTransformIdentity.
This is not a complete answer, but might help if you don't get something better: When the device is rotated, the top-level window's frame does not change. Instead, a transform gets applied that rotates everything 90 degrees (or 180 degrees), and then the subviews will get resized to fit in the new coordinate system.
From Apple's PhotoScroller sample code:
We have to use our paging scroll view's bounds, not frame, to calculate the page placement. When the device is in landscape orientation, the frame will still be in portrait because the pagingScrollView is the root view controller's view, so its frame is in window coordinate space, which is never rotated. Its bounds, however, will be in landscape because it has a rotation transform applied.
In short, the view's frame is not affected by device rotations, but its bounds is.