Почему некоторые из моих UIViews смещаются после навигации?

В некоторых моих проектах приложений или только для некоторых UIViews, после pushController navigationController, мое новое представление будет сдвинуто с окна на высоту строки состояния. В результате я помещу этот код в метод viewDidLoad.

CGRect  frameAt = [self.view frame];
CGRect  statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
frameAt.origin.y += statusBarFrame.size.height;
[self.view setFrame: frameAt];

Мне не кажется, что это намерение XCode и Interface Builder, поэтому я подозреваю, что я делаю что-то принципиально неправильное с SDK во время моего дизайна представления. Кроме того, в редких случаях, когда мне не нужно менять свое мнение, я действительно не знаю, какая разница в двух подходах к разработке.

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

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

Ответ 1

Я использовал образец кода Apple NavBar, чтобы попытаться воспроизвести эту проблему.

приложениеDidFinishLaunching изначально выполняется следующим образом:

[window addSubview:navigationController.view];
[window makeKeyAndVisible];

Если я изменил его на это:

UIViewController *shellController = [[UIViewController alloc] initWithNibName:nil bundle:nil];
[shellController.view addSubview:navigationController.view];
[window addSubview:shellController.view];
[window makeKeyAndVisible];

Затем я получаю пробел.

Однако, если я только это сделаю:

UIView *shell = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[shell addSubview:navigationController.view];
[window addSubview:shell];
[window makeKeyAndVisible];

Затем все выглядит нормально.

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

Ответ 2

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

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

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

Вы можете установить свойство авторазрешения для каждого поднабора в Interface Builder в инспекторе размеров (тот, который имеет значок линейки). В анимации белый квадрат представляет корневой вид контроллера вида, красное поле представляет выбранное в данный момент подвью. Вы заметите, что подвью привязывается к верхнему левому углу корневого представления по умолчанию. Это прекрасно, если размер представления никогда не изменяется, но мы знаем, что это не так. Если у вас есть подпункты, которые вы хотите отобразить внизу, неважно, что нужно, тогда вам нужно сыграть с диаграммой слева. Способ его работы заключается в том, что выбрана одна из четырех линий вокруг края, тогда фиксируется расстояние между этим краем корневого представления и краем подвью. Поэтому, если вы хотите, чтобы подвью отображалось внизу, вам нужно убедиться, что выбрана самая нижняя строка, а не верхняя. Две линии в середине влияют на изменение размера подзона при изменении размера корневого представления. Так, например, если у вас было представление таблицы, которое вы хотели бы занять всю высоту экрана, вы должны убедиться, что выбрана внутренняя вертикальная линия. Это называется моделью распорок и пружин.

Если вы добавляете subviews программно, вам нужно установить свойство autoresizingMask для каждого поднабора. Здесь объяснение.

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

Ответ 4

текст ссылки

Здесь обсуждалась аналогичная ошибка.

Также анимация установлена ​​в НЕТ? Попробуйте установить его в YES, поскольку это решило аналогичную проблему, с которой я столкнулся.

Ответ 5

Ответ Моши был очень полезен, так как я, наконец, осознал смысл пунктирных/сплошных линий в IB для управления свойствами изменения размеров элементов UIView.

Однако при настройке этих свойств не была решена аналогичная проблема, с которой я столкнулся с одним из моих взглядов. Этот вид имел статус и верхний бар, определенный в IB. Это был немного тяжелый, содержащий UIWebView, который будет загружать HTML-строку в viewWillAppear и несколько других элементов интерфейса.

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

Что, наконец, решило мои проблемы, и мои оставшиеся волосы добавили строку:

    self.view.frame = [[UIScreen mainScreen] bounds];

внутри

-(void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

С тех пор, как содержимое моего представления удерживается на месте, несмотря на резкие изменения ориентации устройства.