Проблемы с просмотром высоты (продолжение)

Это продолжение проблемы, которую я здесь (которая до сих пор не решена): ссылка

Но это может помочь понять, в чем проблема. Я создал простой тестовый проект ( "Пустое приложение" ) и добавил контроллер представления с XIB файлом (флажок: "С XIB файлом для пользовательского интерфейса" ). Код выглядит следующим образом:

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"didLoad: %@",NSStringFromCGRect(self.view.bounds));

    // Do any additional setup after loading the view from its nib.
}

-(void) viewDidAppear:(BOOL)animated
{
    NSLog(@"didAppear: %@",NSStringFromCGRect(self.view.bounds));

}

Это вывод:

2013-07-26 17:05:28.502 testtest[5926:c07] didLoad: {{0, 0}, {320, 548}}
2013-07-26 17:05:28.506 testtest[5926:c07] didAppear: {{0, 0}, {320, 460}}

Почему они разные?

(ps. Я тестирую симулятор 6.1)

Ответ 1

Когда вызывается метод viewDidLoad, ваш контроллер просмотра только что был загружен из вашей раскадровки или XIB, поэтому размеры представления равны тем, которые у вас есть в XIB (они выглядят как размеры высоты iPhone 5).

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

В вашем случае похоже, что ваш раскадровки или XIB файл установлен на размер экрана iPhone 5 (548 = 1136/2 - строка состояния), и вы тестируете в симуляторе или устройстве с iPhone 480x320 экран, поэтому размер изображения будет уменьшен до 460 пунктов, чтобы он поместился на экране.

Ответ 2

Это может иметь прекрасный смысл.

ViewDidLoad называется лениво при первом доступе controller.view, поэтому к этому времени кадр еще не установлен. Это означает, что вы не можете рассчитывать на размеры кадров/границ в этой точке, потому что оно будет содержать только значение по умолчанию (хотя во многих случаях оно будет правильным). В ViewDidAppear кадр обычно устанавливается, хотя, если ваш родительский контроллер устанавливает какую-либо анимацию, вы также можете иметь временное состояние кадра вместо конечного, но это не обычно, поскольку по соглашению этот метод вызывается, когда представление уже отображается.

Например, если вы загружаете представление из файла IB, кадр, который вы получите в ViewDidLoad, является тем, который у вас есть в файле IB, но, возможно, конечный размер для вашего представления меньше/больше, а затем вы получите еще один в своем ViewDidAppear.

Вместо этого вы должны создать все свои изменяемые размеры (используйте Spring & Struts, AutoLayout или любую другую аналогичную альтернативу), чтобы они были правильно отображены, когда установлен фрейм.

Ответ 3

Когда a ViewController представляет свое представление, оно обычно сжимает чтобы его рамка не перекрывала строку состояния устройств.

Итак, когда вы NSLog в viewDidLoad, View я еще не загружен, поэтому ViewController еще не сжал кадр, но в viewDidAppear он выполнил изменение размера. В UIViewController есть свойство wantsFullScreenLayout

Установка этого свойства в YES приводит к тому, что контроллер вида чтобы он заполнял весь экран, включая область под статус бар. (Конечно, для этого должно произойти окно, в котором диспетчер представлений должен иметь размер, чтобы заполнить весь экран, включая область под строкой состояния.) Обычно вы устанавливаете это свойство для YES в случаях, когда у вас есть полупрозрачная строка состояния и хотите, чтобы ваше мнение было видимым за этим видом.

Ответ 4

Насколько я знаю, ViewDidLoad установит границы для вашего приложения, как определено, в RootViewController/XIB файле для корневого представления или, возможно, AppDelegate.

Если вы определяете границы приложений (не уверены, в каком из них), функции ViewDidLoad во всем приложении будут изначально заданы в соответствии с этим.

Как только View будет загружен и готов к "появлению", могут потребоваться фактические оценки. Поэтому рекомендуется запрашивать ограничения/размеры в методах ViewWillAppear/ViewDidAppear.

Ответ 5

-viewDidLoad вызывается при первом вызове viewController.view. Он вызывается перед возвратом представления. Это имеет очень важное значение. Для того, чтобы представление отображалось или было задано, его необходимо добавить в окно или другое представление.

Как это происходит? Это выглядит как [window addSubview:viewController.view].

Таким образом, полностью загруженное представление необходимо, прежде чем оно может быть помещено в иерархию представлений. Это накладывает ограничения на self.view при использовании в -viewDidLoad.

  • self.view.superview и self.view.window всегда будет nil.
  • self.view еще не рассчитан на self.view.superview.

При таком понимании вы можете видеть, как self.view не может знать конечный размер при вызове -viewDidLoad.


UPDATE

Если вам нужно применить настраиваемый макет к подзонам представления, вы можете захотеть рассмотреть подклассу UIView и использовать -[UIView layoutSubviews].

Если у вас возникли проблемы с -viewWillAppear: вместо -viewDidAppear:? -viewWillAppear: вызывается перед отображением вида, поэтому при изменении размера представления у вас не будет необычных визуальных эффектов.