webentwicklung-frage-antwort-db.com.de

Warum wird viewWillAppear nicht aufgerufen, wenn eine App aus dem Hintergrund zurückkommt?

Ich schreibe eine App und muss die Ansicht ändern, wenn der Benutzer auf die App schaut, während er telefoniert.

Ich habe die folgende Methode implementiert:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"viewWillAppear:");
    _sv.frame = CGRectMake(0.0, 0.0, 320.0, self.view.bounds.size.height);
}

Es wird jedoch nicht aufgerufen, wenn die App in den Vordergrund zurückkehrt.

Ich weiß, dass ich Folgendes umsetzen kann:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];

aber ich will das nicht tun. Ich würde es vorziehen, alle meine Layoutinformationen in die viewWillAppear: -Methode einzutragen und alle möglichen Szenarien zu behandeln.

Ich habe sogar versucht, viewWillAppear: von applicationWillEnterForeground: aufzurufen, aber ich kann anscheinend nicht genau feststellen, welcher der aktuelle Ansichtscontroller zu diesem Zeitpunkt ist.

Kennt jemand den richtigen Weg, um damit umzugehen? Ich bin sicher, ich vermisse eine offensichtliche Lösung.

265
Philip Walton

Die Methode viewWillAppear sollte im Kontext dessen verwendet werden, was in Ihrer eigenen Anwendung vor sich geht, und nicht im Kontext dessen, dass Ihre Anwendung in den Vordergrund gestellt wird, wenn Sie von einer anderen Anwendung zu ihr zurückkehren.

Mit anderen Worten, wenn sich jemand eine andere Anwendung ansieht oder einen Anruf entgegennimmt, dann wechselt er zurück zu Ihrer App, die zuvor im Hintergrund ausgeführt wurde, und zu Ihrem UIViewController, der bereits sichtbar war, als Sie Ihre App verlassen haben. was es betrifft, ist es nie verschwunden und es ist immer noch sichtbar - und so wird viewWillAppear nicht aufgerufen.

Ich empfehle, das viewWillAppear nicht selbst aufzurufen - es hat eine bestimmte Bedeutung, die Sie nicht untergraben sollten! Ein Refactoring, das Sie durchführen können, um den gleichen Effekt zu erzielen, kann wie folgt aussehen:

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

- (void)doMyLayoutStuff:(id)sender {
    // stuff
}

Dann lösen Sie auch doMyLayoutStuff aus der entsprechenden Benachrichtigung aus:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doMyLayoutStuff:) name:UIApplicationDidChangeStatusBarFrameNotification object:self];

Es gibt keine Möglichkeit zu erkennen, welcher der 'aktuellen' UIViewController ist. Aber Sie können Wege finden, um das zu umgehen, z. Es gibt delegierte Methoden von UINavigationController, um herauszufinden, wann ein UIViewController darin dargestellt wird. Sie könnten so etwas verwenden, um den neuesten UIViewController zu verfolgen, der vorgestellt wurde.

pdate

Wenn Sie die Benutzeroberflächen mit den entsprechenden Autoresizing-Masken für die verschiedenen Bits auslegen, müssen Sie sich manchmal nicht einmal mit dem manuellen Layout Ihrer Benutzeroberfläche befassen - es wird nur behandelt ...

192
occulus

Swift

Kurze Antwort

Verwenden Sie einen NotificationCenter Beobachter anstelle von viewWillAppear.

override func viewDidLoad() {
    super.viewDidLoad()

    // set observer for UIApplication.willEnterForegroundNotification
    NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)

}

// my selector that was defined above
@objc func willEnterForeground() {
    // do stuff
}

Lange Antwort

Um herauszufinden, wann eine App aus dem Hintergrund zurückkommt, verwenden Sie einen NotificationCenter - Beobachter anstelle von viewWillAppear. Hier ist ein Beispielprojekt, das zeigt, welche Ereignisse wann stattfinden. (Dies ist eine Anpassung von diese Objective-C-Antwort .)

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: UIApplication.didBecomeActiveNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, 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")
    }

}

Beim ersten Start der App lautet die Ausgabereihenfolge:

view did load
view will appear
did become active
view did appear

Nachdem Sie die Home-Taste gedrückt und die App wieder in den Vordergrund gebracht haben, lautet die Ausgabereihenfolge:

will enter foreground
did become active 

Wenn Sie also ursprünglich versucht haben, viewWillAppear zu verwenden, dann UIApplication.willEnterForegroundNotification ist wahrscheinlich was Sie wollen.

Hinweis

Ab iOS 9 müssen Sie den Beobachter nicht mehr entfernen. Die Dokumentation besagt:

Wenn Ihre App auf iOS 9.0 und höher oder MacOS 10.11 und höher abzielt, müssen Sie die Registrierung eines Beobachters in seiner dealloc -Methode nicht aufheben.

178
Suragch

Verwenden Sie das Notification Center in der viewDidLoad: - Methode Ihres ViewControllers, um eine Methode aufzurufen und von dort aus das zu tun, was Sie in Ihrer viewWillAppear: - Methode tun sollten. Das direkte Aufrufen von viewWillAppear: Ist keine gute Option.

- (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");
}
138
Manju

viewWillAppear:animated:, meines Erachtens eine der verwirrendsten Methoden in den iOS-SDKs, wird in einer solchen Situation, d. h. beim Anwendungswechsel, niemals aufgerufen. Diese Methode wird nur in Abhängigkeit von der Beziehung zwischen der Ansicht des View Controllers und dem Fenster der Anwendung aufgerufen, dh die Nachricht wird nur dann an einen View Controller gesendet, wenn ihre Ansicht im Fenster der Anwendung und nicht auf dem Bildschirm angezeigt wird .

Wenn Ihre Anwendung in den Hintergrund wechselt, sind für den Benutzer offensichtlich nicht mehr die obersten Ansichten des Anwendungsfensters sichtbar. Aus Sicht Ihres Anwendungsfensters sind sie jedoch immer noch die obersten Ansichten und sind daher nicht aus dem Fenster verschwunden. Diese Ansichten sind vielmehr verschwunden, weil das Anwendungsfenster verschwunden ist. Sie sind nicht verschwunden, weil sie von das Fenster verschwunden sind.

Wenn der Benutzer zurück zu Ihrer Anwendung wechselt, werden sie daher offensichtlich auf dem Bildschirm angezeigt, da das Fenster erneut angezeigt wird. Aber aus der Sicht des Fensters sind sie überhaupt nicht verschwunden. Daher erhalten die View-Controller niemals das viewWillAppear:animated Botschaft.

33
MHC

Einfach versuchen, es so einfach wie möglich zu machen, siehe Code unten:

- (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");


}
3
ConfusedDeer