Подтвердить что ты не робот

Программно определить максимальный размер используемого кадра для UIView

Я видел несколько подобных вопросов, но ни один из них не касается моей конкретной необходимости. Я хочу, чтобы иметь возможность написать общий вспомогательный метод, который возвращает максимальный размер используемого кадра для UIView, принимая во внимание, имеет ли приложение какую-либо комбинацию строки состояния, панели навигации и/или панели вкладок, поскольку я нахожу себя в этом все время.

Определение метода будет как расширение UIScreen:

+ (CGRect) maximumUsableFrame;

Получение размера с или без строки состояния можно получить из

[UIScreen mainScreen].applicationFrame

но я не могу определить способ определения наличия навигационной панели или панели вкладок. Я думал о поддержании некоторых глобальных флагов в своем делете приложения, но это кажется действительно неуклюжим и останавливает код, являющийся общим и повторно используемым. Я также рассмотрел передачу UIView в качестве параметра, получение окна просмотра, затем rootViewController, а затем просмотр, если установлено свойство навигационного контроллера. Если это так, проверьте, скрыт ли навигационный контроллер. Все очень неуклюжие, если вы спросите меня.

Любые мысли будут оценены.

Dave

EDIT: включение идей из ответа Калеба в случае, если это полезно для всех:

// 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 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;
}
4b9b3361

Ответ 1

Я думаю, вы помещаете свой метод в неправильное место. UIScreen знает о экране, но он (и не должен) ничего не знает о том, что отображается на экране. Это контроллер представления, который отвечает за управление представлением, так что там, где принадлежит метод. Кроме того, поскольку максимальный кадр зависит от конфигурации конкретного контроллера представлений, это должен быть метод экземпляра, а не метод класса. Я думаю, вы должны добавить категорию в UIViewController с помощью метода:

- (CGRect) maximumUsableFrame;

Он по-прежнему довольно общий, доступный для всех контроллеров представлений, но в то же время имеет доступ к свойствам контроллера просмотра, таким как navigationController и tabBarController.

Ответ 2

Используйте 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];
    }
}

Ответ 3

Чтобы заставить это работать, пришлось использовать границы приложений и переключатель ориентации, чтобы выяснить, с какой стороны должна быть удалена строка состояния. Это копия и настройка исходного кода. Я сделал быстрое приложение, которое запускает этот алгоритм, используя комбинации 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 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;
}