Почему мне приходится вручную устанавливать рамку моего вида в viewDidLoad? - PullRequest
30 голосов
/ 20 июля 2011

У меня довольно простая настройка с UINavigationController внутри UITabBarController.Я хочу программно разметить представление rootViewController этого navcontroller, но когда я смотрю на self.view.frame внутри viewDidLoad, я получаю это (например, в landscape ):

1. view frame: {{20, 0}, {748, 1024}} // looks like an odd portrait mode

Затем я автоматически поворачиваюсь к Портрету, и получаю это:

2. view frame: {{0, 0}, {768, 911}}

Затем, когда я возвращаюсь к Пейзажу, кадр теперь такой:

3. view frame: {{0, 0}, {1024, 655}}

И далеесобытия автоповорота переключатся между значениями кадра № 2 и № 3.

Чтобы обойти странность # 1, я сейчас делаю это в viewDidLoad:

if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
    self.view.frame = CGRectMake(0, 0, 768, 911);
} else {
    self.view.frame = CGRectMake(0, 0, 1024, 655);
}

Я чувствую, что здесь явно что-то упущено.Почему стандартный кадр представления не соответствует кадру, когда он автоматически поворачивается назад в ту же ориентацию?Разве рамка просмотра не установлена ​​в исходную ориентацию?Очень смущенный ...

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

Что я делаю не так?

ОБНОВЛЕНИЕ: отключение всех элементов авторазмера на представлении изменения приводит к результату №1:

view frame: {{0, 0}, {748, 1024}}

Это кажется чуть ближе, но все же не совпадает# 3.

Ответы [ 2 ]

98 голосов
/ 20 июля 2011

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

Это помогает понять, что происходит, когда загружается и отображается представление контроллера представления:

  1. Что-то впервые обращается к свойству view контроллера представления.Это может происходить в вашем собственном коде или в UIKit в ответ на действие пользователя, например, выбор вкладки.

  2. UIKit лениво загружает представление вашего контроллера представления, вызывая loadView, если оно определеноили загрузив представление из NIB, указанное в initWithNibName:bundle:.Если ничего не существует, UIKit просто загружает пустое представление.

  3. UIKit вызывает viewDidLoad после того, как представление и его подпредставления были полностью загружены. В этот момент кадр представления будет таким, каким он был установлен в NIB или в loadView.

  4. Что-то требуетUIKit для отображения вида вашего контроллера.Опять же, это может быть действие пользователя, например нажатие на вкладку, или явный вызов метода в вашем коде, например pushViewController:animated: или presentModalViewController:animated:.

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

  6. UIKit вызывает viewWillAppear:. Теперь должен отображаться размер кадра. (?) РЕДАКТИРОВАТЬ: Возможно, это больше не соответствует действительности.См. Комментарии ниже.

  7. UIKit отображает представление с анимацией или без нее.

  8. Вызовы UIKit viewDidAppear:.

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

Если вы хотите построить иерархию представлений вручную, рекомендуемое место для выполнениятак в loadView.Поскольку вы сами создаете представление в этом методе, вы можете инициализировать его фрейм так, как вам нравится.Размер, который вы выбираете, не имеет большого значения, так как UIKit, скорее всего, изменит его на вас.Просто убедитесь, что вы правильно задали свои авторазмерные маски.

0 голосов
/ 20 июля 2011

В вашем классе будет метод

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations    return YES; }

Поместите свой кадр в этот метод ... Тогда он будет работать нормально.

Например:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{
        // Return YES for supported orientations    
        if(interfaceOrientation == UIDeviceOrientationPortrait || UIDeviceOrientationPortraitUpsideDown)
                self.view.frame = CGRectMake(0, 0, FRAME.WIDTHinPOTRAIT, FRAME.HEIGHTinPOTRAIT);
        else if(interfaceOrientation == UIDeviceOrientationLandscapeRight || UIDeviceOrientationLandscapeLeft)
                self.view.frame = CGRectMake(0, 0, FRAME.WIDTHinLANDSCAPE, FRAME.HEIGHTinLANDSCAPE);

        return YES; 
}

FRAME.WIDTH> желаемая ширина FRAME.HEIGHT> желаемая высота

...