Як отримати висоту та ширину екрана залежно від орієнтації?


96

Я намагаюся програмно визначити поточну висоту та ширину мого додатка. Я використовую це:

CGRect screenRect = [[UIScreen mainScreen] bounds];

Але це дає ширину 320 та висоту 480, незалежно від того, чи знаходиться пристрій у книжковій або альбомній орієнтації. Як я можу визначити поточну ширину та висоту (тобто залежно від орієнтації пристрою) головного екрана?

Відповіді:


164

Можна використовувати щось подібне UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) визначення орієнтації, а потім відповідно використовувати розміри.

ТАКОЖ, під час зміни орієнтації, як у UIViewController's

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

Використовуйте передану орієнтацію, toInterfaceOrientationоскільки статусBarOrientation статусу UIA додатка все одно вказуватиме на стару орієнтацію, оскільки вона ще не змінилася (оскільки ви всередині willобробника подій).

Підсумок

До цього є кілька пов’язаних повідомлень, але, здається, кожна з них вказує на те, що вам потрібно:

  1. Подивіться, [[UIScreen mainScreen] bounds]щоб отримати розміри,
  2. Перевірте, в якій орієнтації ви перебуваєте, та
  3. Облік висоти рядка стану (якщо показано)

Посилання

Робочий кодекс

Зазвичай я не заходжу так далеко, але ти викликав мій інтерес. Наступний код повинен зробити трюк. Я написав категорію щодо застосування UIA. Я додав методи класу для отримання 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

Інші думки

Ви можете зайнятися отриманням розмірів, переглянувши rootViewControllerвластивість UIWindow . Я дивився на це в минулому, і він аналогічним чином повідомляє про однакові розміри як у портретному, так і в альбомному режимі, за винятком того, що він повідомляє про обертання:

(gdb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] подання]

<UILayoutContainerView: 0xf7296f0; кадр = (0 0; 320 480); перетворення = [0, -1, 1, 0, 0, 0]; автоматичний розмір = W + H; шар = <CALayer: 0xf729b80 >>

(gdb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] подання]

<UILayoutContainerView: 0xf7296f0; кадр = (0 0; 320 480); автоматичний розмір = W + H; шар = <CALayer: 0xf729b80 >>

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

Однак ... Все-таки було б краще зробити вищезазначені 3 кроки під резюме. Почніть возитися з UIWindows, і ви дізнаєтесь дивні речі, як-от показ UIAlertView змінить клавіатурне вікно UIApplication, щоб вказати на нове вікно UIWart, яке створив UIAlertView. Хто знав? Я виявив помилку, покладаючись на keyWindow, і виявив, що вона так змінилася!


5
Це здається настільки елементарним завданням, що у мене виникають проблеми з переконанням, що мені потрібно зламати власний код, щоб визначити щось подібне.
MusiGenesis

2
Я спробую інше рішення та перепоштую, якщо це спрацює. Цей сайт є настільки агресивним, якщо ви не відповідаєте швидко, ви можете також взагалі не відповідати. ха-ха ...: DI сподіваюся, що моя відповідь є принаймні корисною. Знову ж таки, я спробую щось інше дуже швидко.
Сем

1
Чудово! (BTW, у вас є цікавий інтерес) :-)
Vamos

1
Якщо ви використовуєте applicationFrameзамість bounds(на UIScreen), вам не доведеться віднімати висоту рядка стану.
aopsfan

2
stackoverflow.com/questions/24150359/… mainScreen().bounds.size перетворився на орієнтацію залежно від iOS 8 і далі
Джеральд

39

Це мій код рішення! Цей метод може додати до категорії Categroy класу NSObject, або ви можете визначити клас власного користувальницького класу 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, як зазначено у властивості меж UIScreen Apple, документ Apple :

Обговорення

Цей прямокутник вказаний у поточному просторі координат, який враховує будь-які обертання інтерфейсу, що діють для пристрою. Тому значення цього властивості може змінюватися, коли пристрій обертається між орієнтацією портрета та пейзажу.

тому для розгляду сумісності нам слід виявити версію 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 ;
}

Приблизно так само, як і моя відповідь, лише вона пропускає, якщо вона знаходиться у книзі «Портрет догори ногами». Це має значення лише в тому випадку, якщо ви підтримуєте таку орієнтацію.
Роберт Вагстафф,

2
@Monjer не слід називати методи, які не виконують GET-запит, з префіксом i зі словом get. currentScreenBoundsDependOnOrientation - краща назва методу
bogen

1
@ Hakonbogen.yes може бути, ви маєте рацію, оскільки декларація “peroperty” автоматично генерує метод встановлення / отримання, і це може призвести до конфлікту імен, що суперечить умовам імен objc. Дякуємо за вашу пораду.
монджер

Приємно, що Apple нарешті мовчазно визнала, що їх код обертання був повним безладом, і щойно почав розповідати нам, які прокляті розміри мають поточну орієнтацію. Шкода, що до версії 8 потрібно було потрапити туди.
MusiGenesis

30

Ось зручний макрос:

#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)

14

У 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

Це має бути прийнятою відповіддю. Сучасний та сучасний.
SarpErdag

Скористайтеся цією відповіддю для iios 8 і вище.
iPhoneDeveloper

10

Станом на 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 ;
}

8

якщо вам потрібен розмір, який залежить від орієнтації, і у вас є вид, ви можете просто використовувати:

view.bounds.size

ВЕЛИКИЙ! Рішення KISS = Нехай буде простим і дурним
bsorrentino

3
Поцілунок не означає "Тримай це просто і дурно" - LOL! Це означає "Тримай просто, дурне!" :-)
Ерік ван дер Нойт

Крім того, ця відповідь, очевидно, працює лише в тому випадку, якщо відомо, що ваш вигляд є точно на весь екран. Але, якби це було так, то, мабуть, у вас немає оригінальної проблеми, розміщеної ОП.
Ерік ван дер Нойт,

5

Я написав категорію 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

1
Для мене це виглядає як найчистіша відповідь. Голосовано.
Ерік ван дер Нойт,

5

Ось швидкий спосіб отримати розміри екрану, що залежать від орієнтації:

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


0
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());

0

Однак у 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;
}

0

використовувати -> setNeedsDisplay () для подання, яке потрібно змінити.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.