Смещение на UIWindow addSubview
У меня есть приложение на основе UITabBar, которое прекрасно работает. При определенных обстоятельствах я вместо этого показываю другой UIViewController. Что меня беспокоит, так это то, что мне нужно настроить рамку так, чтобы тестовое перо (и только тестовое перо!) Отображалось правильно. (В противном случае вид находится ниже строки состояния).
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
if (condition) {
UIViewController *vc = [[UIViewController alloc] initWithNibName:@"Test" bundle:nil];
// FIXME this should NOT be required
CGRect r = vc.view.frame;
r.origin.y += 20;
vc.view.frame = r;
[window addSubview:vc.view];
[window makeKeyAndVisible];
return;
}
[window addSubview:tabViewController.view];
[window makeKeyAndVisible];
}
Так что, возможно, что-то не так с тестовым пером? Не может быть Тестовый наконечник работает как новый в новом проекте. И новый чистый кончик показывает те же симптомы. Что-то должно быть не так с пером MainWindow, верно? Но UITabBarController отображает просто отлично.
Я немного смущен и у меня кончаются идеи. Любые предложения, как отследить это?
4 ответа
Добавление корневого представления в ваше окно UIWindow может быть сложным, поскольку окно всегда перекрывает строку состояния. Поэтому кадр вашего корневого представления должен быть сброшен [[UIScreen mainScreen] applicationFrame]
чтобы он не перекрывал и строку состояния. Обычно мы не должны беспокоиться об этом, потому что UIViewController изменяет фрейм для нас... за исключением случаев, когда это не так. Вот сделка:
- Если вы создаете свой контроллер вида и его вид в одном и том же NIB и вкладываете вид под контроллером вида, он автоматически настроит рамку вида.
- Если вы создаете свой контроллер вида и его вид в том же NIB, но подключаете вид к контроллеру вида через розетку контроллера, а не вкладываете его, контроллер не будет корректировать рамку вида автоматически.
- Если вы создаете свой контроллер представления в одном NIB и подключаете его к представлению, определенному в отдельном NIB, устанавливая свойство IB "Имя NIB" контроллера представления в IB, он будет корректировать кадр представления автоматически, но только если у вас также есть " Изменение размера вида из NIB "проверено.
- Если вы создадите свой контроллер представления, вызвав -initWithNibName:bundle:, он не будет автоматически корректировать кадр представления.
- UITabBarController ожидает, что его представление будет добавлено в качестве корневого представления окна, и поэтому всегда корректирует свой собственный кадр представления, чтобы автоматически соответствовать кадру приложения. (В результате вы заметите странный разрыв в 20 пикселей, если вы когда-нибудь добавите представление UITabBarController как подпредставление чего-либо, кроме окна.)
Я предполагаю, что Apple решила, что -initWithNibName: bundle: обычно не будет использоваться для создания корневого представления окна, поэтому она не корректирует кадр в вашем случае. Изменение размера вручную, как вы сделали, это хорошо, и на самом деле рекомендуется в Руководстве по программированию View Controller для iPhone OS, но вы действительно должны использовать [[UIScreen mainScreen] applicationFrame]
поскольку строка состояния не всегда имеет высоту 20 пикселей (например, она выше, когда вы разговариваете по телефону).
Это намного проще и также работает (iOS 4.0 и выше)
MyRootViewController *vc = [[MyRootViewController alloc] init];
[window setRootViewController:vc];
[vc release];
-setRootViewController автоматически добавляет вид контроллера в окно, поэтому вам не нужно об этом беспокоиться. Это свойство (неатомное, сохраняемое), поэтому его освобождение после назначения его окну фактически передает владение объектом UIWindow и будет освобождено (и, следовательно, освобождено), когда окно будет освобождено. Конечно, вы можете создать переменную экземпляра, сохранить ссылку на нее и выпустить в -dealloc, если вы хотите что-то сделать с ней в других методах делегата приложения. Я предпочитаю вышеупомянутый метод, поскольку он заботится об очистке автоматически.
Если вы не знаете, вы можете также освободить контроллеры представления сразу после добавления их представлений в любое другое представление в качестве подпредставления или представления представления контроллеров модального представления. Всякий раз, когда представление удаляется или извлекается из стека представлений, его соответствующие контроллеры также освобождаются.
Вам не нужно использовать initWithNibName, просто...alloc] init]; Сделаю.
Я предполагаю, что ваш UITabBarController
является выходом IB, так что когда applicationDidFinishLaunching:
называется, он уже инициализирован. Попробуйте сделать следующее: сразу после создания экземпляра контроллера представления выполните:
[vc setWantsFullScreenLayout:YES];
Просто чтобы подтвердить то, что было сказано выше: вот код, который мне пришлось использовать:
#define MAIN_SCREEN_OFFSET_PIXELS 20
- (void) pushDownViewOnMainScreen {
CGRect r = [[UIScreen mainScreen] applicationFrame];
r.origin.y -= MAIN_SCREEN_OFFSET_PIXELS;
self.view.frame = r;
}
- (void) viewDidLoad {
[self pushDownViewOnMainScreen];
// ...
}