2

I having problems getting an accurate reading for heights and widths. So I made this quick and dirty app to test the situation.

Here is the code:

@interface wwfpViewController ()
@property (nonatomic, strong) UIView * box;
@property (nonatomic, strong) UILabel * info;
@end

@implementation wwfpViewController
@synthesize box,info;

- (void)viewDidLoad {
    [super viewDidLoad];

    box=[[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
    [box setBackgroundColor:[UIColor darkGrayColor]];
    [box setAutoresizesSubviews:YES];
    [box setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];

    info=[[UILabel alloc] initWithFrame:CGRectMake(10, 10, 300, 300)];
    [info setTextColor:[UIColor whiteColor]];
    [info setBackgroundColor:[UIColor blackColor]];
    [info setLineBreakMode:NSLineBreakByWordWrapping];
    [info setNumberOfLines:10];
    [info setText:@"..."];

    [self.view addSubview:box];
    [box addSubview:info];

    [self updateInfo];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(updateView:)
                                                 name:UIApplicationDidChangeStatusBarOrientationNotification
                                               object:nil];

}

- (void) updateInfo {
    CGFloat selfHeight=self.view.frame.size.height;
    CGFloat selfWidth=self.view.frame.size.width;
    CGFloat boxHeight=box.frame.size.height;
    CGFloat boxWidth=box.frame.size.width;
    int deviceOrientation=[[UIDevice currentDevice] orientation];
    int statusOrientation=[[UIApplication sharedApplication] statusBarOrientation];

    NSString * str=[NSString stringWithFormat:@"[height x width] \nself: [%f x %f] \nbox: [%f x %f] \ndevice: %d status: %d",selfHeight,selfWidth,boxHeight,boxWidth,deviceOrientation,statusOrientation];

    [info setText:str];
}

- (void) updateView: (NSNotification*) notify {
    [self updateInfo];
}


@end

When I test this on an iPad, initially in portrait mode, the info label reports the following:

[height x width]
self: [1004.000000 x 768.000000]
box: [1004.000000 x 768.000000]
device: 0 status: 1

This is correct!

And then when I rotate the iPad to landscape, I get these readings:

[height x width]
self: [768.000000 x 1004.000000]
box: [1004.000000 x 768.000000]
device: 3 status: 3

Actual height x width: 748 x 1024

But when I test this on the iPad when its in landscape orientation, the info label reports:

[height x width]
self: [1024.000000 x 748.000000]
box: [1024.000000 x 748.000000]
device: 0 status: 3

Actual height x width: 748 x 1024

Then when I rotate the iPad to portrait, I get these readings:

[height x width]
self: [748.000000 x 1024.000000]
box: [748.000000 x 1024.000000]
device: 1 status: 1

Actual height x width: 1004 x 768

I rotate it back to landscape and then I get these readings:

[height x width]
self: [768.000000 x 1004.000000]
box: [1004.000000 x 768.000000]
device: 3 status: 3

Actual height x width: 748 x 1024

In all cases the box UIView covers the entire screen, so it is auto adjusting to the orientation changes correctly. These results are consistent from the simulator and testing it on an actual iPad, and I have similar experiences on an iPhone.

After this, I have a few questions:

  1. What am I doing wrong?
  2. Why is the height and width for self.view different from the height and width for box when the two look visually identical?
  3. How can I accurately obtain the overall height and width of the screen or a view, irrespective of orientation changes.

  4. Because [UIDevice ... orientation] reports as zero the first time it is used, should I just ignore it altogether and just stick with [UIApplication ... statusBarOrientation]?
Daddy
  • 9,045
  • 7
  • 69
  • 98
Jimmery
  • 9,783
  • 25
  • 83
  • 157
  • 1
    `NSLog(@"NSStringFromCGRect(@"%@",self.view.frame);` in `viewDidAppear:` method. not in `viewDidLoad:`. – TheTiger Aug 13 '13 at 15:54
  • And if you want to get the screen size so I recently gave an answer [here](http://stackoverflow.com/questions/18207038/height-and-width-for-landscape-mode-is-showing-wrong/18207812#18207812). – TheTiger Aug 13 '13 at 15:55
  • putting this code in `viewDidAppear:` makes no difference. – Jimmery Aug 13 '13 at 15:56
  • 1
    You should do layout in the `viewWillLayoutSubview` method, not in `viewDidLoad`. – rmaddy Aug 13 '13 at 15:56
  • After appearing the view it gives correct height and width of `self.view` is not it ? Well I generally calculate it manually like above link. – TheTiger Aug 13 '13 at 15:57
  • Putting this code in `viewWillLayoutSubviews` still reports the height and width wrongly. Please give my code a try and see for yourself. – Jimmery Aug 13 '13 at 15:58
  • @TheTiger I was hoping to be able to just obtain an accurate reading for the height and width, without calculating it manually. Please copy and paste my code above into Xcode and see if you get similar results, its very puzzling. – Jimmery Aug 13 '13 at 16:00
  • And what you get when you try it in `viewDidAppear:`. Actually I'm home and don;t have mac so can't test it. But sure I will try it tomorrow. – TheTiger Aug 13 '13 at 16:02
  • Does your app/view controller actually support all of the different orientations (does the view controller rotate)? Don't use the notification. `UIViewController` has plenty of methods you should implement for dealing with rotations. – rmaddy Aug 13 '13 at 16:02
  • And also don't use autoresizing method instead of it change box's frame in `didRotateOrientation..` method to `box.frame = self.bounds`. – TheTiger Aug 13 '13 at 16:06
  • @rmaddy I support all the different orientations. Please give my code a go and see if you get the same strange results. – Jimmery Aug 13 '13 at 16:07
  • `- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{NSLog(@"NSStringFromCGRect(@"%@",self.view.frame);};` Have you tried it ? @Jimmery – TheTiger Aug 13 '13 at 16:12
  • @rmaddy - `viewDidAppear:` makes difference when you come into viewController in landscape mode. – TheTiger Aug 13 '13 at 16:13
  • http://stackoverflow.com/questions/18207038/height-and-width-for-landscape-mode-is-showing-wrong/18207812#18207812 – TheTiger Aug 13 '13 at 16:14
  • i have the same issue i have used the performselector after delay 0.3. it gives perfect reasult. – Sunny Shah Aug 14 '13 at 04:47
  • @Sunnyshah You were facing problem with `window` size or `self.view` size ? – TheTiger Aug 14 '13 at 05:30
  • @The Tiger self.view size – Sunny Shah Aug 16 '13 at 04:03

5 Answers5

10

Check the bounds of the views rather than the frame:

CGFloat selfHeight=self.view.bounds.size.height;
CGFloat selfWidth=self.view.bounds.size.width;
CGFloat boxHeight=box.bounds.size.height;
CGFloat boxWidth=box.bounds.size.width;

Also, I would use the UIViewController method for orientation changes and remove the NSNotificationCenter observer.

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    [self updateInfo];
}

Finally, the first call to get the correct size should be in viewWillAppear as it will be incorrect in viewDidLoad:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self updateInfo];
}
Ian L
  • 5,553
  • 1
  • 22
  • 37
1

I tried your code and found one mistake here.

Cause of bug- You didn't make app navigationController based in appdelegate. Set your window's rootViewController to navigationController don't know why but viewController's based view doesn't give the correct frame.

My Opinion- Don't use notification here when you have already a method
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation which is call after orientation changed. Well You are using notification then NP this is just my opinion.

One more thing I would like to say

box = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];

Why don't you simply do

box = [[UIView alloc] initWithFrame:self.view.bounds];

Your Code is okay. Just set your window's rootViewController to navigationController OR tabbarController.

This is Sample Code.

TheTiger
  • 13,264
  • 3
  • 57
  • 82
  • This didnt fix it. Perhaps I am doing it wrong - can you show me your code? Also, `-didRotateFromInterfaceOrientation` still gives me false readings when the iPad is landscape. – Jimmery Aug 14 '13 at 08:18
  • @Jimmery - Ok let me show you code .. See Sample code I have edited my answer. And also check what `viewDidAppear:` effects as you were saying that doesn't make sense. – TheTiger Aug 14 '13 at 09:14
  • Im sorry, but after copy and pasting your code, I get the exact same results. Thanks for your help though. – Jimmery Aug 14 '13 at 10:23
  • @Jimmery Just download the sample and run it. Nobody can help you more than this. – TheTiger Aug 14 '13 at 10:24
0

From Apple docs

Discussion When a view’s bounds change, that view automatically resizes its subviews according to each subview’s autoresizing mask. You specify the value of this mask by combining the constants described in UIViewAutoresizing using the C bitwise OR operator. Combining these constants lets you specify which dimensions of the view should grow or shrink relative to the superview. The default value of this property is UIViewAutoresizingNone, which indicates that the view should not be resized at all.

When more than one option along the same axis is set, the default behavior is to distribute the size difference proportionally among the flexible portions. The larger the flexible portion, relative to the other flexible portions, the more it is likely to grow. For example, suppose this property includes the UIViewAutoresizingFlexibleWidth and UIViewAutoresizingFlexibleRightMargin constants but does not include the UIViewAutoresizingFlexibleLeftMargin constant, thus indicating that the width of the view’s left margin is fixed but that the view’s width and right margin may change. Thus, the view appears anchored to the left side of its superview while both the view width and the gap to the right of the view increase.

If the autoresizing behaviors do not offer the precise layout that you need for your views, you can use a custom container view and override its layoutSubviews method to position your subviews more precisely.

It probably has to do with autoresizing masks read more about it here.

Community
  • 1
  • 1
robahl
  • 559
  • 1
  • 6
  • 13
0

myview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];

Working for me

Softlabsindia
  • 791
  • 6
  • 11
0

I've made macros vWidth and vHeight that will handle all of this logic properly, with fallbacks:

#define sWidth [[UIScreen mainScreen] bounds].size.width
#define sHeight [[UIScreen mainScreen] bounds].size.height

#define vWidth (\
(^float (void){\
BOOL isClassMethod = [[self class] respondsToSelector:_cmd];\
if (isClassMethod) {\
return sWidth;\
} else {\
float __vWidth = ([self isKindOfClass:[UIViewController class]]?((UIViewController *)self).view.frame.size.width:((UIView *)self).frame.size.width);\
if (!__vWidth) {\
__vWidth = ([self isKindOfClass:[UIViewController class]]?((UIViewController *)self).view.superview.frame.size.width:((UIView *)self).superview.frame.size.width);\
}\
if (!__vWidth) {\
__vWidth = sWidth;\
}\
return __vWidth;\
}\
})()\
)
#define vHeight (\
(^float (void){\
BOOL isClassMethod = [[self class] respondsToSelector:_cmd];\
if (isClassMethod) {\
return sHeight;\
} else {\
float __vHeight = ([self isKindOfClass:[UIViewController class]]?((UIViewController *)self).view.frame.size.height:((UIView *)self).frame.size.height);\
if (!__vHeight) {\
__vHeight = ([self isKindOfClass:[UIViewController class]]?((UIViewController *)self).view.superview.frame.size.height:((UIView *)self).superview.frame.size.height);\
}\
if (!__vHeight) {\
__vHeight = sHeight;\
}\
return __vHeight;\
}\
})()\
)
Albert Renshaw
  • 17,282
  • 18
  • 107
  • 195