2012-05-24 4 views
3

Использование пустого шаблона приложения в Xcode 4.3.2, проект создается, поэтому NIB не задействован.Кто изменил мой взгляд? (на iOS)

В FooViewController.m:

-(void) loadView { 
    UIView *view = [[UIView alloc] init]; 
    view.backgroundColor = [UIColor yellowColor]; 
    self.view = view;      
} 

Так вид конкретизируется и назначен self.view. Эти два метода:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    NSLog(@"self.view is %@", self.view); 
} 

-(void) viewDidAppear:(BOOL)animated { 
    NSLog(@"self.view is %@", self.view); 
} 

Первый метод будет распечатать

self.view is <UIView: 0x18e4d0; frame = (0 0; 0 0); layer = <CALayer: 0x182a00>> 

а второй печатает

self.view is <UIView: 0x18e4d0; frame = (0 20; 768 1004); layer = <CALayer: 0x182a00>> 

Так между viewDidLoad и viewDidAppear, вид изменяется. Какой механизм изменил его размер? Можем ли мы на это рассчитывать? Потому что даже Мэтт Нойбург, автор книги «Программирование iOS, 2-е изд.», Делает это так (как на стр. 508).

ответ

0

По умолчанию свойство autoresizesSubviews приведет к изменению размера его подзонов при его отображении.

+0

если добавить '[[UIApplication sharedApplication] keyWindow] .autoresizesSubviews = Нет,' до конца 'viewDidLoad', вид по-прежнему изменяется –

0

self.view фактически не создается, пока он не отображается на экране. Он ленивый. После того, как вызывается viewWillAppear, будет установлен кадр. Да, вы можете доверять этим значениям, потому что они устанавливаются в соответствии с экраном и ориентацией телефона.

self.view - довольно особый вид, я часто не работаю с ним напрямую, я обычно просто добавляю контейнерное представление и рассматриваю его как основной вид. Из-за изменения размера лучше не рассматривать self.view как статическую сущность. Обязательно настройте маски аутсорсинга subview соответствующим образом, чтобы они отображались правильно при изменении self.view.

Чтобы ответить на ваш вопрос, UIKit специально устанавливает раму вида, чтобы учесть размер экрана, ориентацию, навигационные панели, строку состояния, панель инструментов и т. Д. Вам не гарантировано, что рамка, которую вы установили до viewWillAppear будет вызвано, будет таким же. Фактически, self.view будет меняться еще больше, если изменится навигационная панель, ориентация или другие факторы. Поэтому даже после viewWillDisplay вам не гарантируется статический размер для self.view, и если вы его измените, он будет соответствующим образом сброшен, чтобы отразить этот статус устройства.

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

+0

эти две строки NSLog распечатать одно и то же ... –

3

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

Так что, между viewDidLoad и viewDidAppear, представление получает свои размеры и границы, оно полностью надежно и также документировано в документах ViewController.

Обратите внимание, что viewDidLoad будет вызываться каждый раз, когда необходимо создать представления (как в первый раз, так и после предупреждения о низкой памяти - просмотр обычно освобождается, когда требуется память) и viewWillAppear будет вызываться каждый раз, когда контроллер вида находится поверх стека, и его представления будут отображаться.

Посмотрите на документации, связанной с просмотра внешнего вида: http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/RespondingtoDisplay-Notifications/RespondingtoDisplay-Notifications.html#//apple_ref/doc/uid/TP40007457-CH12

+1

, что кажется right ... однако, если пустой метод 'viewWillAppear' определен для переопределения поведения по умолчанию, вид все еще изменяется ... –

+0

Более 100 страниц руководства по программированию ViewController ... вы не можете сказать, что iOS плохо документирована ... –

+0

Вот почему я предложил использовать вид контейнера. Работа с self.view напрямую - это боль, так как размеры x, y всегда остаются неизменными, даже когда дисплей переворачивается. Это особый вид, потому что ОС непосредственно вносит изменения в этот вид. Вам лучше иметь представление как подзаголовок self.view –

0

Похоже viewController «s view изменяет размер , когда вы сделаете это viewController в rootViewController из application» s window. В противном случае вы должны установить его вручную.

Я попробовал этот код:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    self.window.backgroundColor = [UIColor whiteColor]; 

    FooViewController *viewController = [[FooViewController alloc] init]; 

    self.window.rootViewController = viewController; 
    [self.window makeKeyAndVisible]; 

    FooViewController *viewController2 = [[FooViewController alloc] init]; 
    [viewController.view addSubview: [viewController2 view]]; 

    return YES; 
} 

viewController был изменен и viewController2 не было.

также: для viewController назывались все эти методы:

viewDidLoad 
viewWillLayoutSubviews 
viewDidLayoutSubviews 
viewDidAppear 

для viewController2 назывались только viewDidLoad и viewDidAppear.

Также интересно: viewController был изменен до того, как его назвали viewWillLayoutSubviews.

EDIT:

Я полагал, что это заслуживает дальнейшего тестирования. Используя следующий код:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    self.window.backgroundColor = [UIColor whiteColor]; 

    FooViewController *viewController = [[FooViewController alloc] init]; 
    NSLog(@"after init: self.view is %@", viewController.view); 
    self.window.rootViewController = viewController; 
    NSLog(@"after setting to rootViewController: self.view is %@", viewController.view); 
    [self.window makeKeyAndVisible]; 
    NSLog(@"after makeKeyAndVisible: self.view is %@", viewController.view); 

    return YES; 
} 

результаты:

viewDidLoad:       frame = (0 0; 0 0) 
after init:       frame = (0 0; 0 0) 
after setting to rootViewController: frame = (0 0; 0 0) 
after makeKeyAndVisible:    frame = (0 20; 320 460) 
viewWillLayoutSubviews:    frame = (0 20; 320 460) 
viewDidLayoutSubviews:    frame = (0 20; 320 460) 
viewDidAppear:      frame = (0 20; 320 460) 

Так [self.window makeKeyAndVisible]; является виновником.