Сообщение о неправильных границах в ландшафтном режиме - PullRequest
24 голосов
/ 04 марта 2011

У меня возникла проблема с альбомным режимом в приложении iPad.

Я создал очень маленький новый проект, чтобы показать свою проблему. Я установил UIInterfaceOrientation в pList на UIInterfaceOrientationLandscapeRight

В делегате приложения

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    [self.window makeKeyAndVisible];
    MyController *myController = [[MyController alloc] init];
    [self.window addSubview:myController.view];

    return YES;
}

В MyController

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"Bounds Height:%f %f", self.view.bounds.size.height, self.view.bounds.size.width);
}

Я также попытался поместить это в viewDidLoad с теми же результатами

Если я запускаю приложение, удерживая устройство в горизонтальной ориентации,NSLog выводит

Bounds Height: 1004.000000 Bounds Width: 768.000000

Что мне нужно сделать, чтобы получить правильные результаты?Я новичок в этом программировании на iOS, все, что я пытаюсь сделать, это привязать UISlider к нижней части экрана, но когда я получаю неправильные координаты, я не уверен, как это сделать.

Ответы [ 9 ]

58 голосов
/ 13 января 2012

Не думаю, что здесь был дан ответ на первоначальный вопрос, потому что я столкнулся с той же проблемой.

Ключевым моментом здесь является то, что если симулятор / устройство находится в ландшафтном режиме, а затем вы запускаете программу, self.view. (Рамка или границы) получает портретную высоту и ширину.Если ваша программа уже запущена, а затем вы поворачиваете ее, вы получите правильное значение.Это происходит только тогда, когда устройство запускается в альбомной ориентации и не поворачивается.

Кто-нибудь еще нашел решение этой проблемы или знает, что я делаю неправильно?Пожалуйста и спасибо.

Возможное решение

Ранее я вызывал свой метод из метода viewDidLoad.Оказывается, вид все еще переходил.Мне повезло больше, вызвав мою функцию из viewDidAppear, которая вызывается после того, как все сделано.

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

12 голосов
/ 04 марта 2011

Вы слишком рано проверяете размер рамки и границ.

Вместо этого проверяйте их после поворота:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    NSLog(@"Bounds %@", NSStringFromCGRect(self.view.bounds));
    NSLog(@"Frame %@", NSStringFromCGRect(self.view.frame));
}

(Обратите внимание, что я использую NSStringFromCGRect - удобно!)

Это приводит к выводу:

Bounds {{0, 0}, {1024, 748}}
Frame {{0, 0}, {748, 1024}}

Таким образом, в этом выводе фрейм «неправильный», но границы - это то, что вы ожидаете.На самом деле, фрейм на самом деле не неправильный, именно так и происходит вычисление frame -> bounds.Поэтому вам нужно получить доступ к границам.

См. Также, возможно, Имею ли я правильное понимание рамок и границ в UIKit?

Примечание: viewDidAppear вызывается раньше, чем вы думаетев схеме вещей.Согласно документации Apple: «viewDidAppear уведомляет контроллер представления о том, что его представление было добавлено в окно».Другими словами, это может произойти до того, как будет применено любое вращение.

10 голосов
/ 14 марта 2012

У меня была такая же проблема, и я взломал ее так:

- (CGSize)getRotatedViewSize
{
    BOOL isPortrait = UIInterfaceOrientationIsPortrait(self.interfaceOrientation);

    float max = MAX(self.view.bounds.size.width, self.view.bounds.size.height);
    float min = MIN(self.view.bounds.size.width, self.view.bounds.size.height);

    return (isPortrait ? 
            CGSizeMake(min, max) : 
            CGSizeMake(max, min));            
}
2 голосов
/ 01 февраля 2013

Помимо viewDidAppear: убедитесь, что вместо [_window addSubview:_rootViewController.view] используется _window.rootViewController. Это также решило мои проблемы на iOS6.

AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
  _window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  _rootViewController = [[MyRootViewController alloc] init];
  _window.rootViewController = _rootViewController;
  [_window makeKeyAndVisible];
  return YES;
}

MyRootViewController.m:

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  NSLog(@"bounds: %@", NSStringFromCGRect(self.view.bounds));
  UIView *myView = [[UIView alloc] initWithFrame:self.view.bounds];
  [self.view addSubview:myView];
}
2 голосов
/ 19 апреля 2012

viewWillAppear (согласно лекциям Пола Хегарти CS193p) предназначен для инициализации, связанной с геометрией. Поскольку viewDidAppear следует за viewWillAppear, имеет смысл, что и здесь границы правильные. Границы представлений еще не установлены в viewDidLoad.

1 голос
/ 15 июня 2014

Один из комментариев к принятому ответу содержал решение проблемы для меня.

Существует метод, который вы можете переопределить в UIViewController и который называется "viewDidLayoutSubviews", я подключился к нему и откорректировал содержащиеся в нем представления.

И поскольку он вызывается после "viewWillAppear" и перед "viewDidAppear", изменения, которые вы вносите в подпредставления, отображаются, как и ожидалось, без сбоев.

1 голос
/ 08 ноября 2012

Я создал небольшой проект для тестирования фреймов и границ, потому что у меня была та же проблема.Фактически проверка границ в viewDidLoad решила мою проблему.

Я продолжал копать немного и обнаружил, что границы также правильны в методе viewWillLayoutSubviews.Поэтому я предполагаю, что самый «правильный» способ размещения ваших представлений в проекте будет выглядеть так:

  1. .

  2. перенастроить созданные вами представления в viewWillLayoutSubviews, чтобы они находились в правильном положении, когда представление действительно появляется.

0 голосов
/ 05 февраля 2015
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect r = self.view.frame;
CGFloat width = r.size.width;
CGFloat height = r.size.height;
r.size.height = (UIInterfaceOrientationIsLandscape(orientation)) ? MIN(width, height): MAX(width, height);
r.size.width  = (UIInterfaceOrientationIsLandscape(orientation)) ? MAX(width, height): MIN(width, height);
self.view.frame = r;
0 голосов
/ 07 августа 2014

Со мной случилось то же самое.

Вы должны накормить iOS iOS ложкой и поставить эту строку кода здесь, иначе она даст вам неправильный ответ.

-(void) viewWillAppear:(BOOL)animated
{
  [super viewWillAppear:animated];
  //required because device orientation will give you the wrong values
  [UIViewController attemptRotationToDeviceOrientation];
  int orientation = [[UIDevice currentDevice] orientation];
  BOOL isPortrait = false;

  if (orientation == 3 || orientation == 4)
    isPortrait = false;
  else
    isPortrait = true;
  NSLog(@"is portrait %i ?", isPortrait);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...