Подтвердить что ты не робот

Почему мне нужно вручную установить рамку просмотра в viewDidLoad?

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

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

Затем я авторотируюсь в Portrait, и я получаю следующее:

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

Затем, когда я вернусь к Landscape, рамка теперь выглядит следующим образом:

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);
}

Мне кажется, что я, очевидно, что-то пропустил. Почему рамка по умолчанию представления не соответствует кадру, когда он авторотирует обратно в одну и ту же ориентацию? Не отображается ли рамка представления исходной ориентации? Очень смутно...

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

Что я делаю неправильно?

UPDATE: выключение всех элементов автозадания в представлении изменений приводит к результату # 1:

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

Это кажется немного ближе, но все же не соответствует # 3.

4b9b3361

Ответ 1

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

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

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

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

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

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

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

  • UIKit вызывает viewWillAppear:. Теперь кадр должен быть размером, который будет отображаться. (?) EDIT: Это может быть больше недействительным. См. Комментарии ниже.

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

  • UIKit вызывает viewDidAppear:.

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

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

Ответ 2

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

- (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 > желаемая высота