Почему viewWillAppear не вызывается, когда приложение возвращается из фонового режима?
Я пишу приложение, и мне нужно, чтобы изменить мнение, если пользователь смотрит на приложение во время разговора по телефону.
я реализовал следующий метод:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"viewWillAppear:");
_sv.frame = CGRectMake(0.0, 0.0, 320.0, self.view.bounds.size.height);
}
но это не вызывается, когда приложение возвращается на передний план.
Я знаю, что могу реализовать:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
но я не хочу этого делать. Я бы предпочел поместить всю информацию о макете в метод viewWillAppear: и пусть это обрабатывает все возможные вариант развития событий.
Я даже пытался вызвать viewWillAppear: from applicationWillEnterForeground:, но я не могу точно определить, какой текущий контроллер вида в этой точке.
кто-нибудь знает правильный способ справиться с этим? Я уверен, что мне не хватает очевидного решения.
5 ответов:
метод
viewWillAppear
следует принимать в контексте того, что происходит в вашем собственном приложении, а не в контексте вашего приложения, помещаемого на передний план, когда вы переключаетесь на него из другого приложения.другими словами, если кто-то смотрит на другое приложение или принимает телефонный звонок, а затем переключается обратно на ваше приложение, которое было ранее на фоновом режиме, ваш UIViewController, который уже был виден, когда вы покинули свое приложение, "не заботится", так сказать-насколько он обеспокоен, он никогда не исчезал, и он все еще виден - и поэтому
viewWillAppear
не называется.Я рекомендую не называть
viewWillAppear
себя-это имеет определенный смысл, который нельзя разрушить! Рефакторинг, который вы можете сделать для достижения того же эффекта, может быть следующим:- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self doMyLayoutStuff:self]; } - (void)doMyLayoutStuff:(id)sender { // stuff }
тогда и вы запускаете
doMyLayoutStuff
из соответствующего уведомления:[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doMyLayoutStuff:) name:UIApplicationDidChangeStatusBarFrameNotification object:self];
нет никакого способа из коробки, чтобы сказать, что является "текущим" UIViewController путь. Но вы можете найти способы обойти это, например, существуют методы делегирования UINavigationController для выяснения, когда в нем представлен UIViewController. Вы можете использовать такую вещь, чтобы отслеживать последний UIViewController, который был представлен.
обновление
если вы раскладываете UIs с соответствующими масками авторазбора на различных битах, иногда вам даже не нужно иметь дело с "ручной" выкладкой вашего пользовательского интерфейса - он просто получает дело с...
Свифт
короткий ответ:
использовать
NotificationCenter
наблюдатель, а неviewWillAppear
.override func viewDidLoad() { super.viewDidLoad() // set observer for UIApplicationWillEnterForeground NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: .UIApplicationWillEnterForeground, object: nil) } // my selector that was defined above @objc func willEnterForeground() { // do stuff }
ответ
чтобы узнать, когда приложение возвращается из фона, использовать
NotificationCenter
наблюдатель, а неviewWillAppear
. Вот пример проекта, который показывает, какие события происходят при. (Это адаптация эта цель-C ответ.)import UIKit class ViewController: UIViewController { // MARK: - Overrides override func viewDidLoad() { super.viewDidLoad() print("view did load") // add notification observers NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil) } override func viewWillAppear(_ animated: Bool) { print("view will appear") } override func viewDidAppear(_ animated: Bool) { print("view did appear") } // MARK: - Notification oberserver methods @objc func didBecomeActive() { print("did become active") } @objc func willEnterForeground() { print("will enter foreground") } }
на первый запуск приложения, порядок вывода:
view did load view will appear did become active view did appear
после нажатия кнопки home, а затем вернуть приложение на передний план, порядок вывода:
will enter foreground did become active
так что если вы изначально пытаетесь использовать
viewWillAppear
затемUIApplicationWillEnterForeground
- это, наверное, то, что вы хотите.Примечание
начиная с iOS 9 и более поздних версий, вам не нужно удалять наблюдателя. Элемент документация гласит:
если ваше приложение предназначено для iOS 9.0 и позже или macOS 10.11 и позже, вы не нужно отменять регистрацию наблюдателя в его
dealloc
метод.
используйте Центр уведомлений в
viewDidLoad:
метод вашего ViewController для вызова метода и оттуда делать то, что вы должны были сделать в вашемviewWillAppear:
метод. ЗвонюviewWillAppear:
непосредственно не является хорошим вариантом.- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"view did load"); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationIsActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationEnteredForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; } - (void)applicationIsActive:(NSNotification *)notification { NSLog(@"Application Did Become Active"); } - (void)applicationEnteredForeground:(NSNotification *)notification { NSLog(@"Application Entered Foreground"); }
viewWillAppear:animated:
, один из самых запутанных методов в SDK iOS, на мой взгляд, никогда не вызывается в такой ситуации, т. е. переключение приложений. Этот метод вызывается только в соответствии с отношением между представлением контроллера вида и окно приложения, т. е. сообщение отправляется контроллеру вида только в том случае, если его вид отображается в окне приложения, а не на экране.когда ваше приложение идет фон, очевидно, самые верхние виды окна приложения не видны пользователю. Однако в перспективе окна приложения они по-прежнему являются самыми верхними представлениями, и поэтому они не исчезли из окна. Скорее, эти представления исчезли, потому что окно приложения исчезло. Они не исчезли, потому что они исчезли С окне.
поэтому, когда пользователь переключается обратно в приложение, они, очевидно, появляются на экране, потому что снова появится окно. Но с точки зрения окна они вовсе не исчезли. Поэтому контроллеры представления никогда не получают
viewWillAppear:animated
сообщение.
просто пытаюсь сделать это как можно проще см. код ниже:
- (void)viewDidLoad { [self appWillEnterForeground]; //register For Application Will enterForeground } - (id)appWillEnterForeground{ //Application will enter foreground. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(allFunctions) name:UIApplicationWillEnterForegroundNotification object:nil]; return self; } -(void) allFunctions{ //call any functions that need to be run when application will enter foreground NSLog(@"calling all functions...application just came back from foreground"); }