on any other device we use this code to set all views in landscape and everything fits great :
float width=[UIScreen mainScreen].bounds.size.width;
float height= [UIScreen mainScreen].bounds.size.height;
on the iPad 2 only , in order to make it work on landscape we have to swap the width and height, otherwise he puts views on portrait and they seems ugly.
Why is it happens only in iPad2 ?
It's not linked to the device but to iOS. Since iOS 8.0, the bounds is now dependent of the device orientation. I'm also swapping width and height like this :
CGRect ScreenBounds() {
CGRect bounds = [UIScreen mainScreen].bounds;
CGRect tmp_bounds = bounds;
if(bounds.size.width < bounds.size.height) {
bounds.size.width = tmp_bounds.size.height;
bounds.size.height = tmp_bounds.size.width;
}
return bounds;
}
Don't size your views relative to the screen, but relative to their container view. Simple as that.
I had same issue From iOS 8 UIScreen is interface oriented so you will get proper results on devices which are running on iOS 8.
In order to support iOS 7 as well you can use following util method:
+ (CGSize)screenSize {
CGSize screenSize = [UIScreen mainScreen].bounds.size;
if ((NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
return CGSizeMake(screenSize.height, screenSize.width);
}
return screenSize;
}
Related
Our current version of our iphone application in the app store simply stretches the layout to fill the iphone 6 and 6+. After the xcode 7 update, the app just runs as it would on an iphone 4 with black bars at the top. I understand that adding a launch storyboard resolves this. The problem then is that our layout is out of whack on the 6 and 6+.
Obviously fixing the layout to adapt to these screen sizes is what needs to be done, but we are in a pinch and just need to get a behind the scenes function update pushed out to our users ASAP. Is there anyway to go back to the old behavior where the UIView would just stretch to fill the screens?
This won't be an immediate fix, but it's a quick patch that might be worth trying.
If your view is always in portrait, this should work for you. If it requires rotating or a UISplitViewController on iPhone 6(s)+, then it might not.
Scale each subview in your view controller for the new screen size. Declare a couple macros for the device screen size:
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
Then add a method to your view controllers that goes through all subviews to resize each view proportionately based on an iPhone 4 screen size.
- (void)resizeSubviews:(UIView *)view {
CGRect frame = view.frame;
frame.origin.x = frame.origin.x / 320.0f * kScreenWidth;
frame.origin.y = frame.origin.y / 480.0f * kScreenHeight;
frame.size.width = frame.size.width / 320.0f * kScreenWidth;
frame.size.height = frame.size.height / 480.0f * kScreenHeight;
view.frame = frame;
for (UIView *subview in view.subviews) {
[self resizeSubviews:subview];
}
}
Then call that method after adding your subviews with:
[self resizeSubviews:self.view];
There are a lot of ways this could not work, but it covered me during the switch from iPhone 4s to iPhone 5.
I'm new to iOS development and for my assignment, I'm tasked changing updating the ViewController programmatically when the device's orientation changes. I've found a snippet of an answer here, but it doesn't get the job done.
I tried adding this to the viewWillLayoutSubviews of my View Controller, but all I get is an unused variable warning.
CGRect rotatedFrame = [self.view convertRect:self.view.frame fromView:self.view.superview];
viewWillLayoutSubviews and rotation
As a "hint", I've been told it's simple to implement in viewWillLayoutSubviews. Going through and changing all the CGRects in my VC doesn't sound like a couple of lines of code. There's got to be a simpler, more efficient way to do this, but I've only found snippets of solutions digging around on this site. Thanks for reading.
The line of code you are using is assigning a CGRect to the rotatedFrame variable, it's not updating anything on your view controller.
There's many ways to approach this but it depends on what is contained in your view and how it's been configured. Things like Auto Layout for example could let you configure almost everything in Interface Builder and let you avoid doing most things in code.
You've been tasked to do this programatically and since we know that viewWillLayoutSubviews is called every time the device is rotated that's a good place to start. Here's a lazy way I've gone about rotating a video to fit a new orientation using a transformation:
//Vertical
CGSize size = self.view.frame.size;
someView.transform = CGAffineTransformMakeRotation((M_PI * (0) / 180.0))
someView.frame = CGRectMake(0, 0, MIN(size.width, size.height), MAX(size.width, size.height));
//Horizontal
CGSize size = [UIScreen mainScreen].bounds.size;
int directionModifier = ([UIDevice currentDevice].orientation == UIInterfaceOrientationLandscapeLeft) ? -1 : 1;
someView.bounds = CGRectMake(0, 0, MAX(size.width, size.height), MIN(size.width, size.height));
someView.transform = CGAffineTransformMakeRotation((M_PI * (90) / 180.0) *directionModifier);
someView.transform = CGAffineTransformTranslate(someView.transform,0,0);
How many subviews are in your view? Are they grouped? If you're using auto-resizing masks you might get away with only adjusting the frames of one or two views. If your root view has a number of subviews you can loop through views that need similar adjustments to avoid having to write excess code. It really depends on how everything has been set up.
I figured out how to determine the viewWidth and viewHeight and set those as CGFloats. I then added an if-else statement which figures out if the display is in portrait or landscape and sets the problematic calculateButton accordingly.
Apologies for lengthy code, but I've found in searching this site I find "snippets" of answers, but being new to iOS it's difficult to figure out what goes where. Hopefully, this helps someone later. (and hopefully it's correct)
- (void) viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
CGFloat viewWidth = self.view.bounds.size.width;
CGFloat viewHeight = self.view.bounds.size.height;
CGFloat padding = 20;
CGFloat itemWidth = viewWidth - padding - padding;
CGFloat itemHeight = 44;
// Bunch of setup code for layout items
// HOMEWORK: created if-else statement to deal w/ portrait vs. landscape placement of calculateButton.
if (viewWidth > viewHeight) {
// portrait
CGFloat bottomOfLabel = viewHeight;
self.calculateButton.frame = CGRectMake(padding, bottomOfLabel - itemHeight, itemWidth, itemHeight);
} else {
// landscape
CGFloat bottomOfLabel = CGRectGetMaxY(self.resultLabel.frame);
self.calculateButton.frame = CGRectMake(padding, bottomOfLabel + padding, itemWidth, itemHeight);
}
}
I've come across this problem when creating UIImageViews, on the iPhone 6, it fits nicely, but on the 4s, it is huge!, is there a way to add some logic in the ViewDidLoad to change the px size of whatever it is, whether it's a sprite, image, label, etc. ?
Just use auto layout and size classes (You access them in IB down and select the sizi class for iPhone)
There are a few ways to do this, you could use auto-layout, or you can take a different route. If you chose not to take auto-layout, I would recommend do this, however the down side is that there is a lot of programming.
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenHeight = screenRect.size.height;
if (screenHeight == 480) {
// do iPhone 4s stuff
} else if (screenHeight == 568) {
// do iPhone 5, 5s, 5c stuff
} else if (screenHeight == 667) {
// do iPhone 6 stuff
} else if (screenHeight == 736) {
//do iPhone 6 plus stuff
}
I know iOS 8 now returns the proper screen dimensions for the current interface orientation. To get the device width for an orientation in iOS 7 you had to return the height if the orientation is landscape or width if the orientation is portrait, but you can always return the width in iOS 8. I have already taken that into consideration for an app I'm developing that will support iOS 7 and 8. (See code below)
However, I noticed another difference. If I call this method and pass in the orientation that it will be (obtained from willRotateToInterfaceOrientation), on iOS 7 it does return the proper width that it will be but on iOS 8 it returns the width for the old (current) orientation.
How can I get the width of the screen when I know the orientation it currently is or will be on iOS 8 and iOS 7?
While I could just swap the width and height for iOS 8, this would return an incorrect value when this function is called while the device isn't transitioning to a new orientation. I could create two different methods but I'm looking for a cleaner solution.
- (CGFloat)screenWidthForOrientation:(UIInterfaceOrientation)orientation
{
NSString *reqSysVer = #"8.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending) {
return [UIScreen mainScreen].bounds.size.width;
}
CGRect screenBounds = [UIScreen mainScreen].bounds;
CGFloat width = CGRectGetWidth(screenBounds);
CGFloat height = CGRectGetHeight(screenBounds);
if (UIInterfaceOrientationIsPortrait(orientation)) {
return width;
} else if (UIInterfaceOrientationIsLandscape(orientation)) {
return height;
}
return width;
}
Use cases:
iPad running iOS 7:
calling [self screenWidthForOrientation:[UIApplication sharedApplication].statusBarOrientation] in viewDidAppear returns the correct width
calling [self screenWidthForOrientation:toInterfaceOrientation] in willRotateToInterfaceOrientation:toInterfaceOrientation:duration returns the correct width
iPad running iOS 8:
calling [self screenWidthForOrientation:[UIApplication sharedApplication].statusBarOrientation] in viewDidAppear returns the correct width
calling [self screenWidthForOrientation:toInterfaceOrientation] in willRotateToInterfaceOrientation:toInterfaceOrientation:duration returns the incorrect width (what it currently is before the rotation occurs)
Here is my code to calculate correct width and height for iOS7 / iOS8 before applying constraints.
- (void) applyConstraints:(UIInterfaceOrientation)toInterfaceOrientation
{
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
CGFloat heightOfScreen;
CGFloat widthOfScreen;
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
// iOS 8.0 and later code here
if ([UIApplication sharedApplication].statusBarOrientation == toInterfaceOrientation) {
heightOfScreen = screenSize.height;
widthOfScreen = screenSize.width;
} else {
heightOfScreen = screenSize.width;
widthOfScreen = screenSize.height;
}
} else {
if (UIDeviceOrientationIsLandscape(toInterfaceOrientation)) {
heightOfScreen = screenSize.width;
widthOfScreen = screenSize.height;
} else {
heightOfScreen = screenSize.height;
widthOfScreen = screenSize.width;
}
}
//Applying new constraints
...
}
It is not so beautiful but it works =)
In iOS 8, the entire nature of rotation and the coordinate system is totally changed. You should not be using any events like willRotate; they are deprecated. The entire app rotates, including the screen. There are no more rotation transforms; the whole app (screen, window, root view) just gets wider and narrower, and that's how you know something has happened (or you can register to hear about the status bar changing its orientation). If you want to know the device coordinates, independent of rotation, that is what the new screen coordinate spaces are for (fixedCoordinateSpace is the one that doesn't rotate).
My StoryBoard is configured for iPhone4 resolution, and when running on iPhone 5 I'd like a UIView to get bigger (both height&width).
The problem right now is that the view is only getting higher and not wider. What should be the auto-resize configuration in order to achieve this?
You will probably need to use a subclass of UIView with the setFrame: method overridden to catch frame changes.
- (void)setFrame:(CGRect)frame
{
frame.size.width = frame.size.height; // Make the *width* always equal to the *height*. Logic could go here, etc.
[super setFrame:frame]
}
Reference the height of the screen and use some padding values to set your view frame. Below is code to set the frame of a UIView called yourShapeView:
// Get the frame of the screen
CGRect screenFrame = [[UIScreen mainScreen] bounds];
// Set padding from the top and bottom of the shape
CGFloat verticalPadding = 40.0f;
CGFloat horizontalPadding = 20.0f;
// Get the height/width values
CGFloat height = screenFrame.size.height - (verticalPadding * 2);
CGFloat width = screenFrame.size.width - (horizontalPadding * 2);
// Set the size of your shape based on the height and padding
yourShapeView.frame = CGRectMake(horizontalPadding, verticalPadding, width, height);