Перегляд iPhoneБоже не з’являється


116

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

Якщо я буду створювати RootViewControllerта зателефонувати addSubViewна цей контролер, я очікую, що додані представлення (и) будуть підключені до viewWillAppearподій.

Хтось має приклад складної ієрархії програмного перегляду, яка успішно приймає viewWillAppearподії на кожному рівні?

Документи компанії Apple:

Попередження: Якщо подання, яке належить контролеру огляду, додане безпосередньо до ієрархії перегляду, контролер перегляду не отримає це повідомлення. Якщо ви вставляєте або додаєте подання до ієрархії перегляду, і він має контролер перегляду, вам слід надіслати це повідомлення безпосередньо пов'язаному контролеру подання. Якщо не надіслати контролеру перегляду це повідомлення, це запобіжить відображенню будь-якої пов'язаної анімації.

Проблема полягає в тому, що вони не описують, як це зробити. Що означає "безпосередньо"? Як ви "опосередковано" додаєте перегляд?

Я досить новачок у какао та iPhone, тому було б непогано, якби крім базового лайно Hello World були корисні приклади від Apple.


У мене була ця проблема, поки я не зрозумів, що я неправильно розумію цільове використання підкласів UIViewController взагалі. Ознайомтесь із цим запитанням. stackoverflow.com/questions/5691226 / ...
averydev

7
Будьте уважні !!! Більше не правда на iOS 5 !!! Перегляд дзвінківВозникне та переглянетьсяDidAppear автоматично
Вілем Курц

Відповіді:


55

Якщо ви користуєтесь контролером навігації та встановите його делегата, то способи подання {Will, Did} {Appear, Disappear} не використовуються.

Вам потрібно використовувати методи делегації навігаційного контролера:

navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:

2
Я не встановив делегата свого навігаційного контролера, і все-таки метод не викликав. У всякому разі, я встановив це, а потім застосував методи, які ви згадали вище. Дякую.
Димитріс

Я бачу те саме, що і Димитріс
jkp

7
Я щойно перевірив це в iOS4 та iOS5: Це НЕ правда: встановлення делегата Навігаційного
Контролера,

Свіфта 3: FUNC navigationController (_ navigationController: UINavigationController, willShow ViewController: UIViewController, анімовані: Bool) {} І Func navigationController (_ navigationController: UINavigationController, didShow ViewController: UIViewController, анімовані: Bool) {}
Naloiko Eugene

28

Я зіткнувся з цією ж проблемою. Просто надішліть viewWillAppearповідомлення своєму контролеру перегляду, перш ніж ви додасте його як підперегляд. (Є один параметр BOOL, який повідомляє контролеру перегляду, чи він анімований, щоб відображатися чи ні.)

[myViewController viewWillAppear:NO];

Подивіться RootViewController.m на прикладі Metronome.

(Я фактично вважаю, що приклади проектів Apple є чудовими. Є багато більше HelloWorld;)


3
Насправді вам слід зателефонувати viewWillAppear після того, як ви додасте його до підпогляду. Інакше IBOutlets / IBActions не буде підключено.
4thSpace

2
Так, згодом. Створений підвід із XIB, viewWillAppear не викликався. Телефонуй сам і все працює добре.
JOM

Дякую! Це було саме для мене. Мені вручну було додано підпогляд через [scrollView addSubview:controller.view];. Я додав рядок [controller viewWillAppear:NO];після цього і вуаля! Працював як шарм.
Роб С.

Ймовірно, це тому, що ваш UIViewController керує поданням, яке є підзаглядом представлення, керованого іншим UIViewController. Це не передбачена модель дизайну. Щоб отримати додаткові пояснення, перегляньте цю публікацію. stackoverflow.com/questions/5691226 / ...
averydev

6
Будьте уважні !!! Більше не правда на iOS 5 !!! Виклики viewWillAppear та viewDidAppear автоматично. Якщо ви називали це вручну, він би дзвонив двічі.
Вілем Курц

18

Я нарешті знайшов рішення для цього, ЩО РОБОТАЄ!

UINavigationControllerDelegate

Я думаю, що суть її полягає в тому, щоб встановити делегата вашого елемента управління на viewcontroller, в якому він знаходиться, і реалізувати UINavigationControllerDelegateце два способи. Блискуче! Я так схвильований, що нарешті знайшов рішення!


як призначити rootviewcontroller як делегата навігаційного контролера?
Гарго

1
НЕ РОБОТА! спробуйте мінімізувати додаток та максимізувати його
В’ячаслав Герчичев

8

У мене просто було те саме питання. У моїй програмі у мене є 2 навігаційних контролера, які натискають на один і той же контролер перегляду, кожен з них працював в одному випадку, а не в іншому. Я маю на увазі, що при натисканні на той самий контролер виду в першому UINavigationController, viewWillAppearвикликався, але не при натисканні на другий контролер навігації.

Потім я натрапив на цю посаду UINavigationController повинен викликати viewWillAppear / viewWillDisappear методи

І зрозумів, що мій другий контролер навігації переробив viewWillAppear. Скринінг коду показав, що я не дзвонив

[super viewWillAppear:animated];

Я додав це, і це спрацювало!

Документація говорить:

Якщо ви перекриєте цей метод, ви повинні викликати супер в якийсь момент вашої реалізації.


Те саме тут. Заплутався, не телефонуючи супер.
olivaresF

5

Я використовую контролер навігації. Коли я хочу перейти на інший рівень даних або показати свій власний вид, я використовую наступне:

[self.navigationController pushViewController:<view> animated:<BOOL>];

Коли я це роблю, я отримую viewWillAppearфункцію стріляти. Я припускаю, що це кваліфікується як "непряме", оскільки я сам не називаю власне addSubViewметод Я не знаю, чи це на 100% застосовно до вашої програми, оскільки я не можу сказати, чи використовуєте ви навігаційний контролер, але, можливо, це дасть підказку.


5

Спасибі iOS 13.

ViewWillDisappear, ViewDidDisappear, ViewWillAppearІ ViewDidAppearНЕ буде викликаний на представляючи контролер уявлення на прошивці 13 , який використовує нове модальне уявлення , яке не покриває весь екрану.

Кредити збираються на Арек Холько . Він дійсно врятував мені день.

введіть тут опис зображення


4

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

По-друге, ви можете використовувати UITabBarDelegate/ UINavigationBarDelegateпересилати сповіщення вручну, але я виявив, що для того, щоб вся ієрархія викликів перегляду працювала правильно, все, що мені потрібно було зробити, це дзвонити вручну

[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];

і

[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];

.. ПЕРЕКЛАДНО перед тим, як встановити контролери перегляду на відповідний контролер (відразу після розподілу). З цього моменту він правильно називав ці методи на своїх контролерах дочірнього перегляду.

Моя ієрархія така:

window
    UITabBarController (subclass of)
        UIViewController (subclass of) // <-- manually calls [navController viewWill/DidAppear
            UINavigationController (subclass of)
                UIViewController (subclass of) // <-- still receives viewWill/Did..etc all the way down from a tab switch at the top of the chain without needing to use ANY delegate methods

Просто виклик згаданих методів на контролері вкладки / нави вперше переконався, що ВСІ події були перенаправлені правильно. Мені не потрібно було викликати їх вручну з UINavigationBarDelegate/ UITabBarControllerDelegateметодів.

Sidenote: Цікаво, що коли він не працював, приватний метод

- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController 

.. який ви можете бачити зі стакану виклику робочої реалізації, як правило, викликає viewWill/Did..методи, але не робив, поки я не виконав вищезазначене (хоч воно і називалося).

Я думаю, що ДУЖЕ важливо, щоб це UITabBarControllerбуло на рівні вікон, хоча документи, схоже, підтверджують це.

Сподіваюся, що це було зрозуміло (іш), радий відповісти на подальші запитання.


3

Оскільки відповіді не прийнято, і люди (як і я) приземляються тут, я даю свою варіацію. Хоча я не впевнений, що це була первісна проблема. Коли контролер навігації додається як підпогляд до іншого представлення, ви самі повинні викликати методи viewWillAppear / Dissappear тощо:

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [subNavCntlr viewWillAppear:animated];
}

- (void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [subNavCntlr viewWillDisappear:animated];
}

Просто для того, щоб зробити приклад завершеним. Цей код з’являється в моєму ViewController, де я створив і додав навігаційний контролер до подання, яке я розмістив у поданні.

- (void)viewDidLoad {

    // This is the root View Controller
    rootTable *rootTableController = [[rootTable alloc]
                 initWithStyle:UITableViewStyleGrouped];

    subNavCntlr = [[UINavigationController alloc]   
                  initWithRootViewController:rootTableController];

    [rootTableController release];

    subNavCntlr.view.frame = subNavContainer.bounds;

    [subNavContainer addSubview:subNavCntlr.view];

    [super viewDidLoad];
}

.h виглядає приблизно так

@interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
    IBOutlet UIView *subNavContainer;
    UINavigationController *subNavCntlr;
}

@end

У файлі nib у мене є перегляд, а під цим поданням у мене є ярлик зображення та контейнер (інший вигляд), де я ставлю контролер. Ось як це виглядає. Мені довелося декласувати деякі речі, оскільки це була робота для клієнта.

alt текст


3

Перегляди додаються "безпосередньо", зателефонувавши [view addSubview:subview]. Перегляди додаються "опосередковано" такими методами, як смуги вкладок або наві бари, які обмінюються підглядами.

Щоразу, коли ви телефонуєте [view addSubview:subviewController.view], вам слід зателефонувати [subviewController viewWillAppear:NO](або ТАК, залежно від вашого випадку).

У мене виникла ця проблема, коли я реалізував власну власну систему управління кореневим переглядом для підтексту в грі. Додавання дзвінка до viewWillAppear вручну вилікувало мою проблему.


3

Правильний спосіб це зробити, використовуючи UIViewController, що міститься в api.

- (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
     UIViewController *viewController = ...;
     [self addChildViewController:viewController];
     [self.view addSubview:viewController.view];
     [viewController didMoveToParentViewController:self];
}

Це абсолютно правильне сучасне рішення (iOS 9,8,7). Крім того, якщо ви змінюєте вбудований контролер перегляду на ходу, вам потрібно буде зателефонувати [viewController willMoveToParentViewController: nil]; [viewController.view RemoveFromSuperview]; [viewController removeFromParentViewController];
Елі Берк

1
У цьому випадку viewWillAppear:все одно не можуть називатися
В’ячаслав Герчичев

2

Я використовую цей код для контролерів перегляду push і pop:

поштовх:

[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];

поп:

[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];

.. і це прекрасно працює для мене.


2

Дуже поширена помилка полягає в наступному. У вас є один вид UIView* a, а інший - UIView* b. Ви додаєте b до а як підпідгляд. Якщо ви спробуєте викликати viewWillAppear в b, він ніколи не буде звільнений, оскільки це підвід


2

iOS 13 біт мого додатка в прикладі тут. Якщо ви помітили зміну поведінки в iOS 13, просто встановіть наступне, перш ніж натиснути її:

yourVC.modalPresentationStyle = UIModalPresentationFullScreen;

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

Це призведе до того, що ваш додаток поводитиметься так, як це було в попередніх версіях iOS.


1

Я не впевнений у цьому на 100%, але вважаю, що додавання подання до ієрархії подання безпосередньо означає закликати -addSubview:до перегляду контролера перегляду (наприклад, [viewController.view addSubview:anotherViewController.view]) замість натискання нового контролера перегляду на стек навігаційного контролера.


1

Я думаю, що додавання підвідного виду не обов'язково означає, що представлення відобразиться, тому немає автоматичного виклику методу класу, що він буде


1

Я думаю, що вони означають "безпосередньо" - це підключення речей точно так само, як це робить шаблон xcode "Navigation Application", який встановлює UINavigationController як єдиний підвід вікна UIW програми.

Використання цього шаблону - це єдиний спосіб, коли мені вдалося отримати методи Will / Did / Appear / Disappear, що викликаються на об'єкті ViewControllers при натисканні / вискакуванні цих контролерів у UINavigationController. Жодне з інших рішень у відповідях тут не працювало для мене, включаючи реалізацію їх у RootController та передачу їх до (дочірнього) NavigationController. Ці функції (будуть / зробили / з'явилися / зникнуть) викликали в моєму RootController лише після показу / приховування ВК вищого рівня, мого "входу" та навігаційних ВК, а не суб-ВК в контролері навігації, тому я не мав можливості "передайте їх через" VV VV.

Я в кінцевому підсумку використовував функціонал делегата UINavigationController, щоб шукати конкретні переходи, які вимагають подальшої функціональності в моєму додатку, і це працює, але для цього потрібно трохи більше роботи для того, щоб функція зникнення та появи виглядала "імітацією".

Також принциповим є питання, щоб змусити його працювати після того, як сьогодні годинами стукав головою проти цієї проблеми. Будемо дуже вдячні за будь-які фрагменти робочого коду, що використовують користувальницький RootController та дочірню навігаційну машину.


1

У випадку, якщо це допоможе комусь. У мене була подібна проблема, коли мій ViewWillAppearне стріляв по UITableViewController. Після багато розгулу я зрозумів, що проблема полягає в тому, що те, UINavigationControllerщо контролює моє UITableView, не в кореневому режимі. Як тільки я це зафіксував, він зараз працює як чемпіон.


Чи можете ви поділитися, як "ви це зробили?
Brabbeldas

1

У мене просто була ця проблема, і мені було потрібно 3 повних години (2 з яких гугли), щоб виправити її.

Допомогло те, що просто видалити додаток із пристрою / симулятора, очистити та знову запустити .

Сподіваюся, що це допомагає


1
[self.navigationController setDelegate:self];

Встановіть делегата на контролер кореневого виду.


1

Для Свіфта. Спочатку створіть протокол для виклику того, що ви хотіли зателефонувати у viewWillAppear

protocol MyViewWillAppearProtocol{func myViewWillAppear()}

По-друге, створити клас

class ForceUpdateOnViewAppear: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool){
    if let updatedCntllr: MyViewWillAppearProtocol = viewController as? MyViewWillAppearProtocol{
        updatedCntllr.myViewWillAppear()
    }
}

}

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


0

У моєму випадку проблема була у користувальницькій анімації переходу. Коли встановленоmodalPresentationStyle = .custom viewWillAppear не викликається

у спеціальному класі анімації переходу потрібні методи виклику: beginAppearanceTransitionіendAppearanceTransition


0

У моєму випадку це була просто дивна помилка на емуляторі ios 12.1. Зникає після запуску на реальному пристрої.


0

Я створив клас, який вирішує цю проблему. Просто встановіть його як делегата вашого контролера навігації та застосуйте простий один-два способи у вашому контролері перегляду - що буде викликано, коли подання буде показано або було показано через NavigationController

Ось ГІСТ, що показує код


0

ViewWillAppear - метод переосмислення класу UIViewController, тому додавання subView не викличе viewWillAppear, але коли ви представите, натисніть, поп, покажіть, встановітьFront або popToRootViewController з viewController, тоді буде виклик viewWillAppear для представленого viewController.


0

Моя проблема полягала в тому, що viewWillAppear не викликався під час відмовки від каналу. Відповідь полягала в тому, щоб зателефонувати на viewWillAppear (правда) в розмотувану казку в контролері подання, на який ви переглядаєте

@IBAction func unind (for undindSegue: UIStoryboardSegue, ViewController наступнийVC: Будь-який) {

   viewWillAppear(true)
}

-2

Я не впевнений, що це та сама проблема, яку я вирішив.
У деяких випадках метод не виконується звичайним способом, наприклад "[self methodOne]".

Спробуйте

- (void)viewWillAppear:(BOOL)animated
{
    [self performSelector:@selector(methodOne) 
           withObject:nil afterDelay:0];
}

проблему взагалі viewWillAppearне називають
В’ячаслав Герчичев

-3

У будь-який час вам повинно бути активним лише 1 UIViewController. Будь-які підзагляди, якими ви хочете маніпулювати, повинні бути саме такими - subVIEWS - тобто UIView.

Я використовую просту техніку для управління моєю ієрархією зору і ще не стикаюся з проблемою, оскільки я почав робити такі дії. Є два ключові моменти:

  • один UIViewController повинен використовуватися для керування вашим додатком "на екрані"
  • використовувати UINavigationController для зміни поглядів

Що я маю на увазі під "екраном варто"? Це дещо невиразно за призначенням, але, як правило, це функція або розділ вашої програми. Якщо у вас є кілька екранів з однаковим фоновим зображенням, але різні накладки / спливаючі вікна тощо, це повинен бути контролер 1 перегляду та кілька дочірніх переглядів. Ви ніколи не повинні знаходити себе з двома контролерами перегляду. Зауважте, ви все ще можете створити інстанцію UIView в одному контролері перегляду та додати його як підвид іншого контролера перегляду, якщо ви хочете, щоб певні ділянки екрана відображалися у кількох контролерах перегляду.

Щодо UINavigationController - це ваш найкращий друг! Вимкніть панель навігації та вкажіть NO для анімованих, і у вас є чудовий спосіб перемикання екранів на вимогу. Ви можете натискати та виводити контролери перегляду, якщо вони перебувають в ієрархії, або ви можете підготувати масив контролерів перегляду (включаючи масив, що містить єдиний VC) та встановити його як стек перегляду за допомогою setViewControllers. Це дає вам повну свободу змінювати VC, отримуючи при цьому всі переваги роботи в рамках очікуваної моделі Apple та отримання всіх подій тощо.

Ось що я роблю щоразу, коли запускаю програму:

  • почати з вікна програми
  • додайте UINavigationController як rootViewController вікна
  • додайте все, що я хочу, щоб мій перший UIViewController був як rootViewController навігаційного контролера

.

Усі події ведуть правильно і в основному життя добре. Тоді ви можете витратити весь свій час на написання важливих бітів програми і не возитися з спроби вручну зламати ієрархії перегляду у формі.


Немає нічого поганого в тому, що активовано кілька контролерів перегляду; UIViewController має методи, що дозволяють побудувати ієрархію (наприклад, [addChildViewController:]).
Річард

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