UIScreen applicationFrame возвращает неправильный прямоугольник при запуске приложения в альбомной ориентации (iPhone/iPad)
Возникают проблемы с получением правильных границ для моего приложения iPad при запуске его в альбомном режиме. У меня установлены правильные ключи в моем файле Info.plist, и мои контроллеры представления запускаются правильно в альбомной (и портретной, натч).
В моем applicationDidFinishLaunching:
метод я вызываю селектор после 3-секундной задержки, и этот метод вызывает [[UIScreen mainScreen] applicationFrame]
, но он возвращает мне портретную рамку (т.е. высота> ширина).
Кто-нибудь знает, как это исправить? Это пахнет для меня как ошибка (если так, я подам радар), но если это предполагаемое поведение, где это задокументировано?
8 ответов
Когда вы держите iPad в горизонтальной ориентации и запускаете приложение, контроллер представления изначально видит границы для портретной ориентации (даже если в отчетах об ориентации отображается альбомная ориентация). Контроллер представления получит сообщение для поворота в альбомную ориентацию, прежде чем оно появится.
Я никогда не полагаюсь на [[UIScreen mainScreen] applicationFrame]
особенно во время запуска приложения.
При создании представлений в коде используйте суперпредставление, чтобы установить ваш кадр.
Если вы используете xibs с "симулированными элементами интерфейса", они будут иметь правильный размер, и все будет отлично работать.
Приложения на основе UINavigationController
В случае приложения на основе UINavigationController, захват кадра непосредственно из self.navigationController.view
не пытайтесь использовать [self loadView]
а также self.view.superview
, UINavigationController использует "скрытые" подпредставления для выполнения своей работы - поэтому прямое суперпредставление не будет работать.
UINavigationController является особенным, потому что во время запуска приложения контроллер навигации изменяет размеры ваших представлений после loadView
вызывается. При автоматическом изменении размера вы получаете небольшой запас в нижней части экрана.
Почему не UIScreen
[[UIScreen mainScreen] applicationFrame]
не работает надежно (особенно при запуске приложения в альбомной ориентации). Мой опыт показывает, что viewcontroller interfaceOrientation
свойство не будет соответствовать applicationFrame
ориентации.
CGRect bounds = [[UIScreen mainScreen] bounds]; // portrait bounds
if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
bounds.size = CGSizeMake(bounds.size.height, bounds.size.width);
}
Вот как я получаю правильный CGRect, когда контроллер представления находится в альбомной ориентации:
CGRect landscapeBounds;
if (self.view.frame.size.width < self.view.frame.size.height)
landscapeBounds = CGRectMake(self.view.frame.origin.y, self.view.frame.origin.x, self.view.frame.size.height, self.view.frame.size.width);
else
landscapeBounds = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
Это как задумано. Вы должны запросить размер вашего суперпредставления и скорректировать при необходимости.
[[UIScreen mainScreen] applicationFrame]
всегда будет возвращать портретный прямоугольник, даже если приложение находится в ландшафтном режиме. Это связано с тем, что UIWindow
на самом деле никогда не вращается, а просто меняет преобразование rootViewController.view
вместо.
Чтобы убедиться, что вы можете напечатать корневой объект просмотра в портретном и ландшафтном режимах, вы увидите что-то вроде этого:
Портрет:
<UIView: 0x96290e0; frame = (0 20; 768 1004); ...
Пейзаж:
<UIView: 0x96290e0; frame = (0 20; 768 1004); transform = [0, 1, -1, 0, 0, 0]; ...
Итак, добавьте образ запуска и присвойте ему суффикс -568h, согласно руководствам Apple.
Я не понимаю, почему кто-то со здравым смыслом заставил бы системную настройку зависеть от графики; но я только что проверил, и это сработало.
Вот место, которое научило меня после быстрого поиска, я не видел этот ответ выше, подумал, что это будет кому-то полезно.
S
Я попал в ту же проблему при отклонении представления с помощью dismissViewControllerAnimated в плагине Cordova. Я изменил код singingAtom для метода viewWillAppear в MainViewController, размер которого был изменен после закрытия модального представления:
- (void)viewWillAppear:(BOOL)animated
{
CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
UIDeviceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (UIDeviceOrientationLandscapeLeft == orientation ||
UIDeviceOrientationLandscapeRight == orientation)
{
if (appFrame.size.width < appFrame.size.height)
{
appFrame = CGRectMake(appFrame.origin.y, appFrame.origin.x, appFrame.size.height, appFrame.size.width);
}
}
self.view.frame = appFrame;
[super viewWillAppear:animated];
}