以编程方式确定UIView的最大可用帧大小

时间:2011-08-02 15:41:15

标签: ios cocoa-touch uiview uiviewcontroller

我已经看到了几个类似的问题,但没有一个能解决我的具体需求。我希望能够编写一个通用的辅助方法,它返回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;
}

3 个答案:

答案 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;

它仍然相当通用,可供所有视图控制器使用,但同时可以访问视图控制器属性,如navigationControllertabBarController

答案 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;
}