306

私はアプリを書いていますが、ユーザーが電話で話しているときにアプリを見ている場合は、ビューを変更する必要があります。

次の方法を実装しました。

- (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: メソッドに入れ、考えられるすべてのシナリオを処理できるようにしたいと考えています。

applicationWillEnterForeground: から viewWillAppear: を呼び出そうとさえしましたが、その時点で現在のビュー コントローラーがどれであるかを特定できないようです。

これに対処する適切な方法を知っている人はいますか?私は明らかな解決策を見逃していると確信しています。

4

7 に答える 7

232

迅速

簡潔な答え

NotificationCenterではなくオブザーバーを使用してください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
}

長い答え

アプリがバックグラウンドからいつ戻ってくるかを調べるには、NotificationCenterではなくオブザーバーを使用しviewWillAppearます。これは、どのイベントがいつ発生するかを示すサンプル プロジェクトです。(これは、この Objective-C answerの適応です。)

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")
    }

}

アプリを最初に起動したときの出力順序は次のとおりです。

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

ホームボタンを押してからアプリをフォアグラウンドに戻した後の出力順序は次のとおりです。

will enter foreground
did become active 

したがって、最初に使用しようとしていた場合は、おそらくviewWillAppearそれが必要です。UIApplication.willEnterForegroundNotification

ノート

iOS 9 以降では、オブザーバーを削除する必要はありません。ドキュメントには次のように記載されています。

deallocアプリが iOS 9.0 以降または macOS 10.11 以降を対象としている場合、そのメソッドでオブザーバーを登録解除する必要はありません。

于 2015-12-30T12:27:42.047 に答える
213

このメソッド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であるかをすぐに判断できる方法はありません。しかし、それを回避する方法を見つけることができます。たとえば、UIViewController がいつそこに表示されるかを調べるための UINavigationController のデリゲート メソッドがあります。このようなものを使用して、提示された最新の UIViewController を追跡できます。

アップデート

さまざまなビットに適切な自動サイズ変更マスクを使用して UI をレイアウトする場合、UI の「手動」レイアウトを処理する必要さえない場合があります-処理されるだけです...

于 2011-03-11T20:43:26.120 に答える
141

ViewControllerのメソッドで通知センターを使用してviewDidLoad:メソッドを呼び出し、そこからメソッドで行うべきことを実行します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");
}
于 2013-08-28T05:21:40.363 に答える
35

viewWillAppear:animated:私の意見では、iOS SDK で最も紛らわしいメソッドの 1 つである . このメソッドは、View Controller のビューとアプリケーションの windowの間の関係に従ってのみ呼び出されます。つまり、ビューが画面ではなくアプリケーションのウィンドウに表示される場合にのみ、メッセージが View Controller に送信されます。

アプリケーションがバックグラウンドになると、明らかに、アプリケーション ウィンドウの最上位ビューがユーザーに表示されなくなります。ただし、アプリケーション ウィンドウの観点では、それらは依然として最上位のビューであるため、ウィンドウから消えることはありません。むしろ、アプリケーション ウィンドウが消えたため、これらのビューは消えました。窓から消えたから消えたのではありません。

したがって、ユーザーがアプリケーションに戻ると、ウィンドウが再び表示されるため、明らかに画面に表示されているように見えます。しかし、ウィンドウの観点からは、それらはまったく消えていません。したがって、View Controller はviewWillAppear:animatedメッセージを受け取りません。

于 2011-03-11T20:54:30.167 に答える
7

スイフト 4.2 / 5

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground),
                                           name: Notification.Name.UIApplicationWillEnterForeground,
                                           object: nil)
}

@objc func willEnterForeground() {
   // do what's needed
}
于 2019-09-15T10:24:52.640 に答える
3

できるだけ簡単にするために、以下のコードを参照してください。

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


}
于 2015-07-17T03:55:37.527 に答える