目标C:准确地获得UIView的高度和宽度

时间:2013-08-13 15:38:38

标签: objective-c orientation dimensions cgrect

我在获取高度和宽度的准确读数方面遇到了问题。所以我制作了这个快速而又脏的应用来测试这种情况。

以下是代码:

@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

当我在iPad上测试时,最初是在纵向模式下,信息标签会报告以下内容:

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

这是正确的!

然后当我将iPad旋转到风景时,我得到了这些读数:

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

实际高度x宽度:748 x 1024

但是当我在iPad上横向测试时,信息标签会报告:

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

实际高度x宽度:748 x 1024

然后当我将iPad旋转为肖像时,我得到了这些读数:

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

实际高度x宽度:1004 x 768

我将它旋转回风景,然后我得到这些读数:

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

实际高度x宽度:748 x 1024

在所有情况下,box UIView都会覆盖整个屏幕,因此会自动调整方向更改。这些结果与模拟器一致并在实际的iPad上进行测试,我在iPhone上也有类似的经历。

在此之后,我有几个问题:

  1. 我做错了什么?
  2. 为什么self.view的高度和宽度与box的高度和宽度不同,当两者在视觉上完全相同时?
  3. 无论方向如何变化,如何准确获取屏幕或视图的整体高度和宽度。

  4. 由于[UIDevice ... orientation]在第一次使用时报告为零,我应该完全忽略它并坚持使用[UIApplication ... statusBarOrientation]吗?

5 个答案:

答案 0 :(得分:10)

检查视图的边界而不是框架:

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;

另外,我会使用UIViewController方法进行方向更改并删除NSNotificationCenter观察者。

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

最后,要获得正确尺寸的第一次调用应位于viewWillAppear,因为它在viewDidLoad中不正确:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self updateInfo];
}

答案 1 :(得分:1)

我尝试了你的代码,发现了一个错误。

错误原因您没有根据navigationController制作应用appdelegate。将window的{​​{1}} rootViewController设置为navigationController不知道原因,但基于viewController的视图未提供正确的框架。

我的意见 - 如果您已经在方向更改后调用方法
notification,请不要在此使用-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation。那么你正在使用notification然后NP这只是我的意见。

我想说的另一件事

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

你为什么不这么做?

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

您的代码没问题。只需将窗口的rootViewController设置为navigationController或tabbarController。

这是Sample Code

答案 2 :(得分:0)

来自Apple文档

  

讨论当视图的边界发生变化时,该视图会自动更改   根据每个子视图的自动调整遮罩调整其子视图的大小。   您可以通过组合常量来指定此掩码的值   在UIViewAutoresizing中使用C按位OR运算符描述。   通过组合这些常量,您可以指定哪些尺寸   视图应相对于superview增长或缩小。默认   此属性的值是UIViewAutoresizingNone,表示该属性   视图不应该调整大小。

     

如果设置了同一轴上的多个选项,则为默认值   行为是按比例分配大小差异   灵活的部分。柔性部分相对于柔性部分越大   其他柔性部分,它可能越多。例如,   假设此属性包含UIViewAutoresizingFlexibleWidth和   UIViewAutoresizingFlexibleRightMargin常量但不包括   UIViewAutoresizingFlexibleLeftMargin常量,从而表明   视图左边距的宽度是固定的,但视图的宽度是固定的   宽度和右边距可能会改变。因此,视图似乎锚定于   其超视图的左侧同时具有视图宽度和间隙   在视图右侧增加。

     

如果自动调整行为不能提供您的精确布局   需要您的视图,您可以使用自定义容器视图和覆盖   它的layoutSubviews方法可以更精确地定位您的子视图。

这可能与autoresizing masks有关,请参阅here

答案 3 :(得分:0)

  

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

为我工作

答案 4 :(得分:0)

我制作了宏vWidthvHeight,它们可以正确处理所有这些逻辑,并且具有后备功能:

#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;\
}\
})()\
)