Перегляд змін кадру між viewWillAppear: і viewDidAppear:


85

Я виявив дивну поведінку в моєму додатку, коли підключений IBOutletмає свій підключений кадр перегляду між викликами в моєму контролері перегляду до viewWillAppear:і viewDidAppear:. Ось відповідний код у моєму UIViewControllerпідкласі:

-(void)viewWillAppear:(BOOL)animated {
    NSLog(@"%@", self.scrollView);
}

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

і отриманий журнал:

MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 0; 0 0); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>
MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 44; 320 416); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>

Що чітко показує, що кадр змінюється між двома дзвінками. Я хотів зробити налаштування з поданням у viewDidLoadметоді, але якщо вміст недоступний для мене, щоб змінити, поки він не з’явиться на екрані, це здається досить марним. Що може бути?


2
Ви використовуєте авторозкладку? ви додаєте це представлення у програмі Interface builder чи програмно?
Андреа

Увімкнено авторозкладку, і це представлення створюється в IB із розкадрування.
Джумін

1
Я ніколи не користувався раскадровкою, але, можливо, це правильно. Використання рамки авторозкладки для ваших подань встановлюється, коли механізм авторозкладки починає обчислення. Спробуйте запитати те саме одразу після супер - (void) viewDidLayoutSubviews mpethod вашого контролера перегляду.
Андреа

Це успішно запускає мою подію в потрібний час, але цей метод також викликається, коли я виконую будь-яку анімацію у поданні.
Джумін

1
viewDidLayoutSubviewsбув правильним шляхом. Мені просто довелося розмістити весь вміст у підпрогляді, щоб метод не викликався повторно, щоразу, коли я змінював фрейм основного подання.
Джумін

Відповіді:


111

Autolayoutзробив величезну зміну в тому, як ми розробляємо та розробляємо графічний інтерфейс наших поглядів. Однією з головних відмінностей є те, що autolayoutрозмір нашого перегляду змінюється не відразу, а лише тоді, коли це спрацьовує, тобто в певний час, але ми можемо змусити його негайно перерахувати наші обмеження або позначити їх як "потрібні" макету. Це працює як -setNeedDisplay.
Великим викликом для мене було зрозуміти і прийняти те, що нам більше не потрібно використовувати авторозмірні маски, і фрейм став марною властивістю розміщувати наші погляди. Нам більше не потрібно думати про позицію зору, але нам слід думати, як ми хочемо бачити їх у просторі, пов’язаному один з одним.
Коли ми хочемо змішати стару маску автоматичного розміру та авторозкладку, це коли виникають проблеми. Нам слід задуматися про реалізацію авторозкладки дуже скоро і спробувати уникнути змішування старого підходу в ієрархії подань, заснованій на розкладі.
Добре мати представлення контейнера, яке використовує лише маски автоматичної зміни розміру, такі як основний вигляд контролера перегляду, але краще, якщо ми не намагатимемося змішувати.
Я ніколи не користувався раскадровкою, але, можливо, це правильно. Використовуючи авторозкладку, кадр ваших поглядів встановлюється, коли механізм авторозкладки починає обчислення. Спробуйте запитати те саме одразу після супер - (void)viewDidLayoutSubviewsметоду вашого контролера перегляду.
Цей метод викликається, коли механізм авторозкладки закінчив обчислювати кадри ваших переглядів.


5
- (void) viewDidLayoutSubviews - це відповідь для мене! Дуже дякую!
FrizzTheSnail

Ця відповідь насправді не є правильною. Так, звичайно, очевидно, що протягом (5?) Років вам доведеться використовувати авторозкладку. Але буває будь-яка кількість ситуацій ( за допомогою авторозкладки ), коли потрібно, скажімо, додати щось на екран, "безпосередньо перед тим, як воно з’явиться для користувача". (Якщо ви зробите це у viewDidAppear, ви отримаєте мерехтіння. Якщо ви зробите це у viewWillAppear - позиції будуть неправильними.) Фактична відповідь справді полягає у використанні viewDidLayoutSubviews.
Fattie,

add something on a screen, "just before it appears to the user". The actual answer is indeed to use viewDidLayoutSubviews.... ви збираєтеся показати цей погляд багато разів
Андреа

156

З документації:

viewWillAppear:

Повідомляє контролер подання, що його подання збирається додати до ієрархії подання.

viewDidAppear:

Повідомляє контролер подання, що його подання було додано до ієрархії подання.

Як результат, кадри підпроектів ще не встановлені в viewWillAppear:

Відповідним методом модифікації інтерфейсу користувача перед тим, як подання буде показано на екрані, є:

viewDidLayoutSubviews

Повідомляє контролер перегляду, що його подання щойно виклало свої підпрогляди.


2
Тьфу, це дратує. Навіть із формулювання документації здається, ніби viewWillApepar: і viewDidAppear: мають відбуватися безпосередньо один за одним.
Джумін

2 місяці чекаю цієї відповіді ... дякую, я знайшов !! ДУЖЕ ТОБІ ДЯКУЮ!
Рафаель Руїс Муньос

6
Слід зазначити, що viewDidLayoutSubviewsбуде викликатися кілька разів, і не завжди з однаковим кадром, (я думаю, це викликається за допомогою CGRectZero при першому дзвінку іноді). Він отримує виклик для кожного доданого підпрогляду та інших змін у поданні.
bauerMusic

Я цілими днями вкладався в це (viewDidLayoutSubviews викликався кілька разів, в тому числі при відмові від подання), і просто сказав ef з ним, і вклав логіку в оператор if і зробив bool, який встановлюється на true після код запущений один раз. Я думаю, що має бути чистіший спосіб, але вже занадто багато часу на це пішло.
соленоїд

ми повинні дійти до суті цього! viewDidLayoutSubviews жахливий, seNeedDisplay не працює
Yaro

9

дзвінок

self.scrollView.layoutIfNeeded ()

у вашому viewWillAppearметоді. Згодом ви зможете отримати доступ до його кадру, і він матиме те саме значення, що і ви друкуєтеviewDidAppear


1
Ні, це не правильно. Приклад: у вас на екрані є панель навігації (з вашого навігаційного контролера). Навіть після layoutIfNeeded () висота панелі навігації не включається, тому розмір вашого кадру зміниться.
xaphod

Це IS хороший спосіб , щоб змусити повторне обчислення розмірності Scrollview кадру так , що воно відповідає всій ієрархії викликів виду макета , якщо кадр Scrollview пов'язаний з обмеженнями в межах його надтабліци.
smakus

4

У моєму випадку переміщення всіх методів, пов'язаних з кадрами, до

override func viewWillLayoutSubviews()

працював ідеально (я намагався змінити обмеження з розкадровки).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.