Становится ли [UIScreen mainScreen].bounds.size зависимым от ориентации в iOS8?
Я запустил следующий код в iOS 7 и iOS 8:
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
BOOL landscape = (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight);
NSLog(@"Currently landscape: %@, width: %.2f, height: %.2f",
(landscape ? @"Yes" : @"No"),
[[UIScreen mainScreen] bounds].size.width,
[[UIScreen mainScreen] bounds].size.height);
Ниже приводится результат от iOS 8:
Currently landscape: No, width: 320.00, height: 568.00
Currently landscape: Yes, width: 568.00, height: 320.00
По сравнению с результатом в iOS 7:
Currently landscape: No, width: 320.00, height: 568.00
Currently landscape: Yes, width: 320.00, height: 568.00
Есть ли документация с указанием этого изменения? Или это временная ошибка в iOS 8 API?
18 ответов
Да, это зависит от ориентации в iOS8, а не ошибка. Вы можете просмотреть сессию 214 WWDC 2014 для получения дополнительной информации: "Просмотр улучшений контроллера в iOS 8"
Цитата из презентации:
UIScreen теперь ориентирован на интерфейс:
- [UIScreen bounds] теперь ориентирован на интерфейс
- [UIScreen applicationFrame] теперь ориентирован на интерфейс
- Уведомления о рамке строки состояния ориентированы на интерфейс
- Уведомления о кадре клавиатуры ориентированы на интерфейс
Да, это зависит от ориентации в iOS8.
Я написал метод Util для решения этой проблемы для приложений, которые должны поддерживать более старые версии ОС.
+ (CGSize)screenSize {
CGSize screenSize = [UIScreen mainScreen].bounds.size;
if ((NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
return CGSizeMake(screenSize.height, screenSize.width);
}
return screenSize;
}
Да, действительно, размер экрана теперь зависит от ориентации в iOS 8. Иногда, однако, желательно, чтобы размер был зафиксирован в портретной ориентации. Вот как я это делаю.
+ (CGRect)screenBoundsFixedToPortraitOrientation {
UIScreen *screen = [UIScreen mainScreen];
if ([screen respondsToSelector:@selector(fixedCoordinateSpace)]) {
return [screen.coordinateSpace convertRect:screen.bounds toCoordinateSpace:screen.fixedCoordinateSpace];
}
return screen.bounds;
}
Да, теперь это зависит от ориентации.
Я предпочитаю приведенный ниже метод получения размера экрана независимо от ориентации для некоторых из ответов выше, и потому, что он проще, и потому, что он не зависит от кода ориентации (состояние которого может зависеть от время, когда они вызваны) или на проверку версии. Возможно, вы захотите новое поведение iOS 8, но оно будет работать, если вам нужно, чтобы оно было стабильным на всех версиях iOS.
+(CGSize)screenSizeOrientationIndependent {
CGSize screenSize = [UIScreen mainScreen].bounds.size;
return CGSizeMake(MIN(screenSize.width, screenSize.height), MAX(screenSize.width, screenSize.height));
}
В связи с этим вопросом, поскольку он решил мою проблему, вот два определения, которые я использую для расчета ширины и высоты экрана:
#define SCREEN_WIDTH (IOS_VERSION_LOWER_THAN_8 ? (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.width : [[UIScreen mainScreen] bounds].size.height) : [[UIScreen mainScreen] bounds].size.width)
#define SCREEN_HEIGHT (IOS_VERSION_LOWER_THAN_8 ? (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.height : [[UIScreen mainScreen] bounds].size.width) : [[UIScreen mainScreen] bounds].size.height)
#define IOS_VERSION_LOWER_THAN_8 (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
Если вы поддерживаете iOS 7 и iOS 8, это лучшее решение для этой проблемы.
Ты можешь использовать nativeBounds
(Ориентация-независимая)
nativeBounds
Ограничительный прямоугольник физического экрана, измеряется в пикселях. (Только для чтения)
Декларация SWIFT
var nativeBounds: CGRect { get }
Этот прямоугольник основан на устройстве в портретной ориентации. Это значение не изменяется при вращении устройства.
Определение высоты устройства:
if UIScreen.mainScreen().nativeBounds.height == 960.0 {
}
Определение ширины устройства:
if UIScreen.mainScreen().nativeBounds.width == 640.0 {
}
Это не ошибка в iOS 8 SDK. Они сделали границы интерфейса зависимыми. По вашему вопросу о какой-либо ссылке или документации к этому факту я настоятельно рекомендую вам посмотреть View Controller Advancements in iOS 8
это 214 сессия от WWDC 2014. Самая интересная часть (согласно вашим сомнениям) Screen Coordinates
который начинается в 50:45.
Да, это зависит от ориентации в iOS8.
Вот как вы можете получить согласованный способ считывания границ в стиле iOS 8 для версий SDK и OS.
#ifndef NSFoundationVersionNumber_iOS_7_1
# define NSFoundationVersionNumber_iOS_7_1 1047.25
#endif
@implementation UIScreen (Legacy)
// iOS 8 way of returning bounds for all SDK's and OS-versions
- (CGRect)boundsRotatedWithStatusBar
{
static BOOL isNotRotatedBySystem;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
BOOL OSIsBelowIOS8 = [[[UIDevice currentDevice] systemVersion] floatValue] < 8.0;
BOOL SDKIsBelowIOS8 = floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1;
isNotRotatedBySystem = OSIsBelowIOS8 || SDKIsBelowIOS8;
});
BOOL needsToRotate = isNotRotatedBySystem && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
if(needsToRotate)
{
CGRect screenBounds = [self bounds];
CGRect bounds = screenBounds;
bounds.size.width = screenBounds.size.height;
bounds.size.height = screenBounds.size.width;
return bounds;
}
else
{
return [self bounds];
}
}
@end
Мне нужна была быстрая вспомогательная функция, которая сохраняла бы то же поведение, что и iOS7 под iOS8 - это позволило мне поменять [[UIScreen mainScreen] bounds]
звонки и не трогай другой код...
+ (CGRect)iOS7StyleScreenBounds {
CGRect bounds = [UIScreen mainScreen].bounds;
if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
bounds.size = CGSizeMake(bounds.size.height, bounds.size.width);
}
return bounds;
}
Мое решение - это комбинация MaxK и hfossli. Я сделал этот метод на категории UIScreen, и у него нет проверок версий (что является плохой практикой):
//Always return the iOS8 way - i.e. height is the real orientation dependent height
+ (CGRect)screenBoundsOrientationDependent {
UIScreen *screen = [UIScreen mainScreen];
CGRect screenRect;
if (![screen respondsToSelector:@selector(fixedCoordinateSpace)] && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
screenRect = CGRectMake(screen.bounds.origin.x, screen.bounds.origin.y, screen.bounds.size.height, screen.bounds.size.width);
} else {
screenRect = screen.bounds;
}
return screenRect;
}
Приведенный ниже метод можно использовать для определения границ экрана для заданной ориентации, независимо от версии iOS. Этот метод возвращает границы в зависимости от размера экрана устройства и дает одинаковое значение CGRect независимо от версии iOS.
- (CGRect)boundsForOrientation:(UIInterfaceOrientation)orientation {
CGFloat width = [[UIScreen mainScreen] bounds].size.width;
CGFloat height = [[UIScreen mainScreen] bounds].size.height;
CGRect bounds = CGRectZero;
if (UIInterfaceOrientationIsLandscape(orientation)) {
bounds.size = CGSizeMake(MAX(width, height), MIN(width, height));
} else {
bounds.size = CGSizeMake(MIN(width, height), MAX(width, height));
}
return bounds;
}
// For the below example, bounds will have the same value if you run the code on iOS 8.x or below versions.
CGRect bounds = [self boundsForOrientation:UIInterfaceOrientationPortrait];
iOS 8 или выше
Решение для тех, кто хочет узнать размер экрана в пунктах (3,5-дюймовый экран имеет 320 × 480 точек, 4,0-дюймовый экран имеет 320 × 568 точек и т. Д.)
- (CGSize)screenSizeInPoints
{
CGFloat width = [[UIScreen mainScreen] bounds].size.width;
CGFloat height = [[UIScreen mainScreen] bounds].size.height;
if (width > height) {
return CGSizeMake(height, width);
}
else {
return [[UIScreen mainScreen] bounds].size;
}
}
Моя проблема была связана с рамкой UIWindows, которая собиралась в минус. Так сделал код как показано ниже в MyViewController -(NSUInteger)
[[UIApplication sharedApplication] setStatusBarHidden:NO];
[self.view setFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)];
[appDel.window setFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)];
И его работа для меня, попробуйте.
Использовал слегка измененное решение mnemia, которое без проверки версии iOS, с использованием min/max на границах главного экрана.
Мне нужен был CGRect
так получил CGRect
от границ главного экрана и изменил size.width=min(w,h)
, size.height=max(w,h)
, Тогда я назвал эту ОС независимой CGRect
функция в двух местах в моем коде, где я получаю размер экрана для OpenGL
, касаний и т. д. До исправления у меня было 2 проблемы - на IOS 8.x в альбомной ориентации отображать OpenGL
вид был неправильный: 1/4 от полного экрана в левой нижней части. И второе касание вернуло недопустимые значения. Обе проблемы были исправлены, как объяснено. Спасибо!
Вот что я использовал для вычисления правильного прямоугольника:
UIScreen* const mainScreen = [UIScreen mainScreen];
CGRect rect = [mainScreen bounds];
#ifdef __IPHONE_8_0
if ([mainScreen respondsToSelector:@selector(coordinateSpace)])
{
if ([mainScreen respondsToSelector:@selector(fixedCoordinateSpace)])
{
id tmpCoordSpace = [mainScreen coordinateSpace];
id tmpFixedCoordSpace = [mainScreen fixedCoordinateSpace];
if ([tmpCoordSpace respondsToSelector:@selector(convertRect:toCoordinateSpace:)])
{
rect = [tmpCoordSpace convertRect:rect toCoordinateSpace: tmpFixedCoordSpace];
}
}
}
#endif
Просто добавив быструю версию превосходной функции cbartel, отвеченной выше.
func screenSize() -> CGSize {
let screenSize = UIScreen.mainScreen().bounds.size
if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) && UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) {
return CGSizeMake(screenSize.height, screenSize.width)
}
return screenSize
}
Одна вещь, которую я заметил, это то, что порядок поддерживаемых ориентаций интерфейса в Info.plist имеет значение. У меня возникла проблема этого вопроса с моим приложением (которое выполняет ориентацию в коде), но я нигде не указал, что ориентация по умолчанию - Портрет.
Я думал, что ориентацией по умолчанию был Портрет в любом случае.
Переупорядочив itens в Info.plist, поместив Portrait первым, восстановил ожидаемое поведение.
Это даст правильное устройство в iOS7 и iOS8,
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define IS_PORTRAIT UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation)
+ (BOOL)isIPHONE4{
// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){
if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 480.0) {
return YES;
} else {
return NO;
}
// >= iOS 8.0
}else{
if(IS_PORTRAIT){
if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 480.0) {
return YES;
} else {
return NO;
}
}else{
if ([self getDeviceWidth] == 480.0 && [self getDeviceHeight] == 320.0) {
return YES;
} else {
return NO;
}
}
}
}
+ (BOOL)isIPHONE5{
// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){
if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 568.0) {
return YES;
} else {
return NO;
}
// >= iOS 8.0
}else{
if(IS_PORTRAIT){
if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 568.0) {
return YES;
} else {
return NO;
}
}else{
if ([self getDeviceWidth] == 568.0 && [self getDeviceHeight] == 320.0) {
return YES;
} else {
return NO;
}
}
}
}
+ (BOOL)isIPHONE6{
// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){
if ([self getDeviceWidth] == 375.0 && [self getDeviceHeight] == 667.0) {
return YES;
} else {
return NO;
}
// >= iOS 8.0
}else{
if(IS_PORTRAIT){
if ([self getDeviceWidth] == 375.0 && [self getDeviceHeight] == 667.0) {
return YES;
} else {
return NO;
}
}else{
if ([self getDeviceWidth] == 667.0 && [self getDeviceHeight] == 375.0) {
return YES;
} else {
return NO;
}
}
}
}
+ (BOOL)isIPHONE6Plus{
// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){
if ([self getDeviceWidth] == 414.0 && [self getDeviceHeight] == 736.0) {
return YES;
} else {
return NO;
}
// >= iOS 8.0
}else{
if(IS_PORTRAIT){
if ([self getDeviceWidth] == 414.0 && [self getDeviceHeight] == 736.0) {
return YES;
} else {
return NO;
}
}else{
if ([self getDeviceWidth] == 736.0 && [self getDeviceHeight] == 414.0) {
return YES;
} else {
return NO;
}
}
}
}
+ (CGFloat)getDeviceHeight{
//NSLog(@"Device width: %f",[UIScreen mainScreen].bounds.size.height);
return [UIScreen mainScreen].bounds.size.height;
}
+ (CGFloat)getDeviceWidth{
//NSLog(@"Device width: %f",[UIScreen mainScreen].bounds.size.height);
return [UIScreen mainScreen].bounds.size.width;
}
// Вы также можете добавить больше устройств (ieiPad).