Dlaczego viewWillAppear nie jest wywoływany, gdy aplikacja wraca z tła?
Piszę aplikację i muszę zmienić widok, jeśli użytkownik patrzy na aplikację podczas rozmowy przez telefon.
Zaimplementowałem następującą metodę:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"viewWillAppear:");
_sv.frame = CGRectMake(0.0, 0.0, 320.0, self.view.bounds.size.height);
}
Ale nie jest wywoływany, gdy aplikacja wraca na pierwszy plan.
Wiem, że mogę zaimplementować:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
Ale nie chcę tego robić. Wolałbym umieścić wszystkie moje informacje o układzie w metodzie viewWillAppear: i pozwolić, aby obsłużyła wszystkie możliwe scenariusze.
Próbowałem nawet zadzwonić. viewWillAppear: from applicationWillEnterForeground:, ale nie mogę wskazać, który jest bieżącym kontrolerem widoku w tym momencie.
Czy ktoś wie jak sobie z tym poradzić? Jestem pewien, że brakuje mi oczywistego rozwiązania. 5 answers
Metoda viewWillAppear
powinna być brana w kontekście tego, co dzieje się we własnej aplikacji, a nie w kontekście umieszczania aplikacji na pierwszym planie, gdy przełączysz się z powrotem do niej z innej aplikacji.
Innymi słowy, jeśli ktoś patrzy na inną aplikację lub odbiera telefon, a następnie przełącza się z powrotem do aplikacji, która była wcześniej na backgrounded, Twój UIViewController, który był już widoczny po opuszczeniu aplikacji "nie obchodzi", że tak powiem - o ile jest / align = "left" /
Odradzam nazywanie siebie viewWillAppear
- ma to konkretne znaczenie, którego nie należy obalać! Refaktoryzacja, którą możesz zrobić, aby osiągnąć ten sam efekt, może wyglądać następująco:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self doMyLayoutStuff:self];
}
- (void)doMyLayoutStuff:(id)sender {
// stuff
}
Następnie uruchamiasz doMyLayoutStuff
z odpowiedniego powiadomienia:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doMyLayoutStuff:) name:UIApplicationDidChangeStatusBarFrameNotification object:self];
Nie ma wyjętego z pudełka sposobu, aby stwierdzić, który jest 'aktualnym' kontrolerem UIViewController. Ale można znaleźć sposoby wokół że, np. istnieją metody delegatów UINavigationController, aby dowiedzieć się, kiedy UIViewController jest w nim przedstawiony. Możesz użyć tego do śledzenia najnowszego Uiviewcontrollera, który został zaprezentowany.
Update
Jeśli układasz Interfejsy z odpowiednimi maskami automatyzacji na różnych bitach, czasami nawet nie musisz zajmować się "ręcznym" układaniem interfejsu - po prostu się z tym uporasz...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-11 14:51:28
Swift
Krótka odpowiedź
Użyj obserwatora NotificationCenter
zamiast 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
}
Długa odpowiedź
Aby dowiedzieć się, kiedy aplikacja wraca z tła, użyj obserwatora NotificationCenter
zamiast viewWillAppear
. Oto przykładowy projekt, który pokazuje, które wydarzenia zdarzają się, kiedy. (Jest to adaptacja tej odpowiedzi Objective-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")
}
}
Przy pierwszym uruchomieniu aplikacji, Kolejność wyjściowa wynosi:
view did load
view will appear
did become active
view did appear
Po wciśnięciu w tym celu należy użyć przycisku home, a następnie przywrócić aplikację na pierwszy plan, kolejność wyjściowa wynosi:
will enter foreground
did become active
Więc jeśli początkowo próbowałeś użyć viewWillAppear
to UIApplicationWillEnterForeground
jest prawdopodobnie tym, czego chcesz.
Uwaga
[13]}od wersji iOS 9 i nowszych nie trzeba usuwać obserwatora. Dokumentacja stwierdza:Jeśli Twoja aplikacja jest przeznaczona na systemy iOS 9.0 i nowsze lub macOS 10.11 i nowsze, nie trzeba wyrejestrować obserwatora w jego metodzie
dealloc
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-21 05:42:43
Użyj Centrum powiadomień w metodzie viewDidLoad:
Twojego kontrolera Viewcontrollera, aby wywołać metodę i stamtąd zrobić to, co powinieneś zrobić w swojej metodzie viewWillAppear:
. Bezpośrednie wywołanie viewWillAppear:
nie jest dobrym rozwiązaniem.
- (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");
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-23 06:22:15
viewWillAppear:animated:
, jedną z najbardziej mylących metod w zestawach SDK iOS moim zdaniem nigdy nie jest wywoływanie w takiej sytuacji, tj. przełączanie aplikacji. Metoda ta jest wywoływana tylko zgodnie z relacją pomiędzy widokiem kontrolera widoku a oknem aplikacji , tzn. wiadomość jest wysyłana do kontrolera widoku tylko wtedy, gdy jego widok pojawia się w oknie aplikacji, a nie na ekranie.
Gdy aplikacja przechodzi w tło, oczywiście najwyższe widoki aplikacji okna nie są już widoczne dla użytkownika. W perspektywie okna aplikacji są one jednak nadal najwyżej położonymi widokami i dlatego nie znikają z okna. Raczej te widoki zniknęły, ponieważ zniknęło okno aplikacji. Nie zniknęły, ponieważ zniknęły z Okna.
Dlatego, gdy użytkownik przełącza się z powrotem do aplikacji, wydaje się, że pojawiają się na ekranie, ponieważ okno pojawia się ponownie. Ale z z perspektywy okna, wcale nie zniknęły. Dlatego Kontrolery widoku nigdy nie otrzymują wiadomości viewWillAppear:animated
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-11 20:54:30
Po prostu staram się to jak najprostsze zobacz kod poniżej:
- (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");
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-23 06:26:46