我已经看到了几个类似的问题,但没有一个能解决我的具体需求。我希望能够编写一个通用的辅助方法,它返回UIView的最大可用帧大小,考虑到应用程序是否具有状态栏,导航栏和/或标签栏的任意组合,因为我发现自己这样做了时间。
方法定义将作为UIScreen的扩展:
+ (CGRect) maximumUsableFrame;
可以从
获取有或没有状态栏的大小 [UIScreen mainScreen].applicationFrame
属性,但我无法找出确定是否存在导航栏或标签栏的方法。我已经考虑过在我的app委托中维护一些全局标志,但这看起来非常笨重,并且停止了代码的通用性和可重用性。我还考虑将UIView作为参数传递,获取视图的窗口,然后是rootViewController,然后查看是否设置了导航控制器属性。如果是,则检查导航控制器是否隐藏。如果你问我,一切都很笨拙。
任何想法都会受到赞赏。
戴夫
编辑:结合Caleb答案中的想法,以防其他人使用:
// Extension to UIViewController to return the maxiumum usable frame size for a view
@implementation UIViewController (SCLibrary)
- (CGRect) maximumUsableFrame {
static CGFloat const kNavigationBarPortraitHeight = 44;
static CGFloat const kNavigationBarLandscapeHeight = 34;
static CGFloat const kToolBarHeight = 49;
// Start with the screen size minus the status bar if present
CGRect maxFrame = [UIScreen mainScreen].applicationFrame;
// If the orientation is landscape left or landscape right then swap the width and height
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
CGFloat temp = maxFrame.size.height;
maxFrame.size.height = maxFrame.size.width;
maxFrame.size.width = temp;
}
// Take into account if there is a navigation bar present and visible (note that if the NavigationBar may
// not be visible at this stage in the view controller's lifecycle. If the NavigationBar is shown/hidden
// in the loadView then this provides an accurate result. If the NavigationBar is shown/hidden using the
// navigationController:willShowViewController: delegate method then this will not be accurate until the
// viewDidAppear method is called.
if (self.navigationController) {
if (self.navigationController.navigationBarHidden == NO) {
// Depending upon the orientation reduce the height accordingly
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
maxFrame.size.height -= kNavigationBarLandscapeHeight;
}
else {
maxFrame.size.height -= kNavigationBarPortraitHeight;
}
}
}
// Take into account if there is a toolbar present and visible
if (self.tabBarController) {
if (!self.tabBarController.view.hidden) maxFrame.size.height -= kToolBarHeight;
}
return maxFrame;
}
答案 0 :(得分:9)
使用applicationFrame。 [[UIScreen mainScreen] applicationFrame]
这是我用它来截取屏幕截图中的内容。
以下是一些示例代码。
-(UIImage*) crop20PointsifStatusBarShowsUp
{
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame]; //Look at this
float sizeOfStatusBarVar= applicationFrame.origin.y;
if ([BGMDApplicationsPointers statusBarShowUp])
{
CGRect newSize = CGRectMake(0, sizeOfStatusBarVar, self.size.width, self.size.height-sizeOfStatusBarVar);
UIImage * newImage = [self cropUIImageWithCGRect:newSize];
return newImage;
}
else{
return [self copy];
}
}
答案 1 :(得分:7)
我认为你把你的方法放在了错误的地方。 UIScreen了解屏幕,但它不会(也不应该)了解屏幕上显示的内容。视图控制器负责管理视图,因此该方法属于该视图。此外,由于最大帧取决于特定视图控制器的配置,因此这应该是实例方法而不是类方法。我认为您应该使用以下方法向UIViewController添加一个类别:
- (CGRect) maximumUsableFrame;
它仍然相当通用,可供所有视图控制器使用,但同时可以访问视图控制器属性,如navigationController
和tabBarController
。
答案 2 :(得分:0)
要使其工作,必须使用应用程序边界和方向开关来确定应从哪一侧移除状态栏。这是最初发布的代码的复制和调整。我制作了一个快速应用程序,通过使用navbar / tabbar / none和状态栏组合运行此算法,并且它适用于所有场景。
- (CGRect) maxFrame
{
// Start with the screen size minus the status bar if present
CGRect maxFrame = [UIScreen mainScreen].applicationFrame;
// the glass screen size
CGRect maxBounds = [UIScreen mainScreen].bounds;
NSLog(@"MaxFrame for %d: (%f, %f, %f, %f)", self.interfaceOrientation, maxFrame.origin.x, maxFrame.origin.y, maxFrame.size.width, maxFrame.size.height);
NSLog(@"MaxBounds for %d: (%f, %f, %f, %f)", self.interfaceOrientation, maxBounds.origin.x, maxBounds.origin.y, maxBounds.size.width, maxBounds.size.height);
// figure out the offset of the status bar
CGFloat statusBarOffset;
switch (self.interfaceOrientation) {
case UIInterfaceOrientationPortrait:
statusBarOffset = maxFrame.origin.y;
break;
case UIInterfaceOrientationPortraitUpsideDown:
statusBarOffset = maxBounds.size.height - maxFrame.size.height;
break;
case UIInterfaceOrientationLandscapeRight:
case UIInterfaceOrientationLandscapeLeft:
statusBarOffset = maxBounds.size.width - maxFrame.size.width;
break;
}
// If the orientation is landscape left or landscape right then swap the width and height
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
CGFloat temp = maxBounds.size.height;
maxBounds.size.height = maxBounds.size.width;
maxBounds.size.width = temp;
}
// apply status bar to the top of the view
maxBounds.origin.y = statusBarOffset;
maxBounds.size.height -= statusBarOffset;
// Take into account if there is a navigation bar present and visible (note that if the NavigationBar may
// not be visible at this stage in the view controller's lifecycle. If the NavigationBar is shown/hidden
// in the loadView then this provides an accurate result. If the NavigationBar is shown/hidden using the
// navigationController:willShowViewController: delegate method then this will not be accurate until the
// viewDidAppear method is called)
if (self.navigationController && !self.navigationController.navigationBarHidden) {
NSLog(@"has nav bar");
maxBounds.size.height -= self.navigationController.navigationBar.frame.size.height;
maxBounds.origin.y += self.navigationController.navigationBar.frame.size.height;
}
// Take into account if there is a toolbar present and visible
if (self.tabBarController && !self.tabBarController.view.hidden) {
maxBounds.size.height -= self.tabBarController.tabBar.frame.size.height;
NSLog(@"has tab bar");
}
NSLog(@"result for %d: (%f, %f, %f, %f)", self.interfaceOrientation, maxBounds.origin.x, maxBounds.origin.y, maxBounds.size.width, maxBounds.size.height);
return maxBounds;
}