Как получить ориентацию по высоте и ширине экрана?

Я пытаюсь программно определить текущую высоту и ширину моего приложения. Я использую это:

CGRect screenRect = [[UIScreen mainScreen] bounds];

Но это дает ширину 320 и высоту 480, независимо от того, находится ли устройство в портретной или альбомной ориентации. Как определить текущую ширину и высоту (т.е. Зависит от ориентации устройства) моего основного экрана?

Ответ 1

Вы можете использовать что-то вроде UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) для определения ориентации, а затем использовать соответствующие размеры.

ОДНАКО, во время изменения ориентации, как в UIViewController

- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation 
                                 duration:(NSTimeInterval)duration

Используйте ориентацию, переданную в toInterfaceOrientation, поскольку статус UApplicationBarOrientation будет по-прежнему указывать на прежнюю ориентацию, поскольку она еще не изменилась (поскольку вы находитесь внутри обработчика событий will).

Резюме

К этому относится несколько связанных должностей, но каждый из них, по-видимому, указывает, что вам нужно:

  • Посмотрите [[UIScreen mainScreen] bounds], чтобы получить размеры,
  • Проверьте, в какой ориентации вы находитесь, и
  • Учетная запись для высоты строки состояния (если показана)

Ссылки

Рабочий код

Обычно я не зашел так далеко, но вы заинтересовали меня. Следующий код должен сделать трюк. Я написал категорию по UIApplication. Я добавил методы класса для получения currentSize или размера в заданной ориентации, что вы бы назвали в UIViewController willRotateToInterfaceOrientation:duration:.

@interface UIApplication (AppDimensions)
+(CGSize) currentSize;
+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation;
@end

@implementation UIApplication (AppDimensions)

+(CGSize) currentSize
{
    return [UIApplication sizeInOrientation:[UIApplication sharedApplication].statusBarOrientation];
}

+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation
{
    CGSize size = [UIScreen mainScreen].bounds.size;
    UIApplication *application = [UIApplication sharedApplication];
    if (UIInterfaceOrientationIsLandscape(orientation))
    {
        size = CGSizeMake(size.height, size.width);
    }
    if (application.statusBarHidden == NO)
    {
        size.height -= MIN(application.statusBarFrame.size.width, application.statusBarFrame.size.height);
    }
    return size;
}

@end

Чтобы использовать код простого вызова [UIApplication currentSize]. Кроме того, я запускал приведенный выше код, поэтому я знаю, что он работает и сообщает правильные ответы во всех ориентациях. Обратите внимание, что я ставлю строку состояния. Интересно, что мне пришлось вычесть MIN для высоты и ширины строки состояния.

Надеюсь, это поможет.: D

Другие мысли

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

(gdb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] view]

< UILayoutContainerView: 0xf7296f0; frame = (0 0, 320 480); transform = [0, -1, 1, 0, 0, 0]; autoresize = W + H; layer = < CALayer: 0xf729b80 >

(gdb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] view]

< UILayoutContainerView: 0xf7296f0; frame = (0 0; 320 480); AUTORESIZE = W + H; layer = < CALayer: 0xf729b80 >

Не знаете, как работает ваше приложение, но если вы не используете какой-либо навигационный контроллер, у вас может быть UIView под вашим основным видом с максимальной высотой/шириной родительского элемента и с ростом/ростом с родителем. Тогда вы можете сделать: [[[[[[[UIApplication sharedApplication] keyWindow] rootViewController] view] subviews] objectAtIndex:0] frame]. Это выглядит довольно интенсивно на одной линии, но вы получаете идею.

Однако... Было бы лучше сделать вышеуказанные 3 шага под сводкой. Начните возиться с UIWindows, и вы обнаружите странные вещи, например, отображение UIAlertView изменит ключевое слово UIApplication, чтобы указать на новый UIWindow, созданный UIAlertView. Кто знал? После обнаружения ошибки, основанной на keyWindow, я обнаружил, что это так изменилось!

Ответ 2

Это мой код решения! Этот метод может добавить к классу классов NSObject Categroy, или вы можете определить класс Top UIViewController и позволить всем вашим другим UIViewControllers наследовать его.

-(CGRect)currentScreenBoundsDependOnOrientation
{  

    CGRect screenBounds = [UIScreen mainScreen].bounds ;
    CGFloat width = CGRectGetWidth(screenBounds)  ;
    CGFloat height = CGRectGetHeight(screenBounds) ;
    UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;

    if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
        screenBounds.size = CGSizeMake(width, height);
    }else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
        screenBounds.size = CGSizeMake(height, width);
    }
    return screenBounds ;
}

Примечание, после IOS8, как Apple Document свойства UIScreen bounds говорит:

Обсуждение

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

поэтому для рассмотрения совместимости мы должны определить версию IOS и внести изменения, как показано ниже:

#define IsIOS8 (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1)

-(CGRect)currentScreenBoundsDependOnOrientation
{  

    CGRect screenBounds = [UIScreen mainScreen].bounds ;
    if(IsIOS8){
        return screenBounds ;
    }
    CGFloat width = CGRectGetWidth(screenBounds)  ;
    CGFloat height = CGRectGetHeight(screenBounds) ;
    UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;

    if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
        screenBounds.size = CGSizeMake(width, height);
    }else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
        screenBounds.size = CGSizeMake(height, width);
    }
    return screenBounds ;
}

Ответ 3

Вот удобный макрос:

#define SCREEN_WIDTH (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.width : [[UIScreen mainScreen] bounds].size.height)
#define SCREEN_HEIGHT (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.height : [[UIScreen mainScreen] bounds].size.width)

Ответ 4

В iOS 8+ вы должны использовать метод viewWillTransitionToSize:withTransitionCoordinator:

-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    // You can store size in an instance variable for later
    currentSize = size;

    // This is basically an animation block
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {

        // Get the new orientation if you want
        UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

        // Adjust your views
        [self.myView setFrame:CGRectMake(0, 0, size.width, size.height)];

    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
        // Anything else you need to do at the end
    }];
}

Это заменяет метод устаревших анимаций, который не дал информации о размере:

-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration

Ответ 5

В настоящее время параметры экрана iOS 8 верны для текущей ориентации. Это означает, что iPad в альбомной ориентации [UIScreen mainScreen].bounds вернет 768 на iOS <= 7 и 1024 на iOS 8.

Следующее возвращает правильную высоту и ширину для всех выпущенных версий.

-(CGRect)currentScreenBoundsDependOnOrientation
{
    NSString *reqSysVer = @"8.0";
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
        return [UIScreen mainScreen].bounds;

    CGRect screenBounds = [UIScreen mainScreen].bounds ;
    CGFloat width = CGRectGetWidth(screenBounds)  ;
    CGFloat height = CGRectGetHeight(screenBounds) ;
    UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;

    if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
        screenBounds.size = CGSizeMake(width, height);
        NSLog(@"Portrait Height: %f", screenBounds.size.height);
    }else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
        screenBounds.size = CGSizeMake(height, width);
        NSLog(@"Landscape Height: %f", screenBounds.size.height);
    }

    return screenBounds ;
}

Ответ 6

если вы хотите размер, зависящий от ориентации, и у вас есть представление, вы можете просто использовать:

view.bounds.size

Ответ 7

Я написал категорию для UIScreen, которая работает на всех версиях iOS, поэтому вы можете использовать ее вот так:
[[UIScreen mainScreen] currentScreenSize].

@implementation UIScreen (ScreenSize)

- (CGSize)currentScreenSize {
    CGRect screenBounds = [[UIScreen mainScreen] bounds];
    CGSize screenSize = screenBounds.size;

    if ( NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1 ) {  
        UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
        if ( UIInterfaceOrientationIsLandscape(interfaceOrientation) ) {
            screenSize = CGSizeMake(screenSize.height, screenSize.width);
        }
    }

    return screenSize;
}

@end

Ответ 8

Вот быстрый способ получить ориентационный размер экрана:

var screenWidth: CGFloat {
    if UIInterfaceOrientationIsPortrait(screenOrientation) {
        return UIScreen.mainScreen().bounds.size.width
    } else {
        return UIScreen.mainScreen().bounds.size.height
    }
}
var screenHeight: CGFloat {
    if UIInterfaceOrientationIsPortrait(screenOrientation) {
        return UIScreen.mainScreen().bounds.size.height
    } else {
        return UIScreen.mainScreen().bounds.size.width
    }
}
var screenOrientation: UIInterfaceOrientation {
    return UIApplication.sharedApplication().statusBarOrientation
}

Они включены как стандартная функция в моем проекте:

https://github.com/goktugyil/EZSwiftExtensions

Ответ 9

float msWidth = [[UIScreen mainScreen] bounds].size.width*(IS_RETINA?2.0f:1.0f);
float msHeight = [[UIScreen mainScreen] bounds].size.height*(IS_RETINA?2.0f:1.0f);
if ( UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ) {
    os->setWidth(MIN(msWidth, msHeight));
    os->setHeight(MAX(msWidth, msHeight));
} else {
    os->setWidth(MAX(msWidth, msHeight));
    os->setHeight(MIN(msWidth, msHeight));
}

NSLog(@"screen_w %f", os->getWidth());
NSLog(@"screen_h %f", os->getHeight());

Ответ 10

Однако, на iOS 8.0.2:

+ (NSUInteger)currentWindowWidth
{
    NSInteger width = 0;
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    CGSize size = [UIScreen mainScreen].bounds.size;
   // if (UIInterfaceOrientationIsLandscape(orientation)) {
   //     width = size.height;
   // } else {
        width = size.width;
  //  }

    return width;
}