Compute frame of UIView for a given device orientation - iphone

I need to handle all iOS screen ratios (3.5 inches, 4 inches). I am not using autolayout because I need iOS 5.x compatibility.
In my app I need to reorganize my buttons and icons when device orientation changes, switching from Portrait:
Logo
-
Button 1
Button 2
Button 3
to Landscape :
Button 1
Logo Button 2
Button 3
Because of the different screen ratios, I need to adjust height of the Logo in Portrait based on the Y-position of Button 1, and to adjust width of the Logo in Landscape based on the X-position of Button 1.
To provide smooth animation, I would like to implement :
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)
and start an animation that would run in the same timeline than the device's rotation animation. The problem is that I need the target frame of "Button 1" for my computation (the frame after the device rotation) and I only have the frame of its initial state.
If I wait for the initial rotation to complete (which is what I implemented so far), you see that the app performs the rotation and THEN the positioning, which is... not satisfying for me.
So, in one single question, that would give :
"Is there a way to ask for the frame of a UIView given a specific device orientation ? Maybe the storyboard..."
It should be accessible somewhere, because the iOS animation has to compute this information to start its animation right ?

One way to find the screen bounds is to do the following:
CGRect screenBounds = [[UIScreen mainScreen] bounds];

Related

UIButton position depending on device and orientation

I have an UIView in which I load some UIButtons programmatically at certain positions (via plist). The positions are based on the screen size of an 9.7" iPad and landscape orientation.
But naturally the buttons don't stay where they belong when you change the orientation or use it on an 12.9" iPad.
What would be the best solution to handle that issue?
EDIT:
I did it with tow scale factors, one for orientation and one for the device size. I works quite good.

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)

problem with zoom in UIScrollView on iOS 4.0

This is a general question to a specific problem.
I am using a UIScrollView in an app that displays photographs. on iOS < 4.0, zooming works great. the same app running on iOS 4.0.x has problems zooming. specifically, if the image does not fill the view (and black bands appear at top/bottom), the first zoom is jerky and garbage data is shown on the bottom of the screen.
the source code to analyze is way to complex and spread out to adequately share here. Can anyone suggest any areas to look at that might cause this strange behavior?
thanks!
Mark
edit: here's the code from the double tap handler (borrowed from the tapDetectingImageView sample code):
- (void)tapDetectingImageView:(TapDetectingImageView *)view gotDoubleTapAtPoint:(CGPoint)tapPoint {
// double tap zooms in
float newScale = [self zoomScale] * ZOOM_STEP;
CGRect zoomRect = [self zoomRectForScale:newScale withCenter:tapPoint];
[self zoomToRect:zoomRect animated:YES];
}
I can force the weirdness if I change the animated parameter in the call to zoomToRect. when animated is NO, my image becomes 2 images superimposed one on top of the other. the bottom image is the original zoom level, the top image is the new zoom level. if I swipe the screen to pan, the image is refreshed. It's almost as if a call to layoutSubviews or DrawRect is not getting called.
This may or may not be related, but the way that UIScrollView dealt with scale factors changed in an undocumented way in iPhone OS 3.2+.
Previously, if you used -scrollViewDidEndZooming:withView:atScale: to re-render your content by applying the identity transform to the view and then redrawing your image sharply at the new scale factor, UIScrollView would ignore this and keep handing you absolute scale factors based on the initial size of the view.
On iPhone OS 3.2+, UIScrollView now gives you a relative scale factor based on the last time you reset the transform of the content view to be the identity transform. This can lead to significant scaling differences between the various OS versions.

Inactive area after device rotation

I don't understand what's wrong in my very simple application with device rotation :
I built my view with interface builder. (See screen capture here)
I specified <key>UIInterfaceOrientation</key><string>UIInterfaceOrientationLandscapeRight</string> in my info.plist file.
I had a (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {return YES;} in my root view controller.
The area on the left (shown in red on the capture), around 20 pixel width, keeps inactive (nothing append if I hit a button in this area). In fact the full screen is active only in portrait mode, in landscape right mode there is this 20 pixels width inactive area, in landscape left mode this inactive area is on the right, in portrait upside down mode this area is on the bottom.
I read lots of posts and documentation about UIView rotation, but I did not find anything to solve this problem (I tried to play with view.frame and view.bounds without any success).
Anybody has an idea ?
Thanks a lot.
Regards.
Sébastien.
One of your views is probably not autoresized correctly.
After rotation, it still has its old bounds of, for example, 320 x 460. Since views normally don't clip their contained views you don't see a difference.
Events on the other hand are only delivered to views that are contained in their superviews bounds.

"Incorrect" frame / window size after re-orientation in 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.