为什么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:从applicationWillEnterForeground :,但我似乎无法指出哪一个当前的视图控制器在那一点。
有没有人知道处理这个问题的正确方法? 我确定我错过了一个明显的解决scheme。
viewWillAppear
方法应该在您自己的应用程序中发生的事情的上下文中进行,而不是在从另一个应用程序切换回前端的应用程序的上下文中。
换句话说,如果有人看着另一个应用程序或者打个电话,然后切换回你的应用程序,那么你的UIViewController在离开你的应用程序时就已经可见了“不关心”这样说 – 就它而言,它从来没有消失,它仍然是可见的 – 所以viewWillAppear
不会被调用。
我build议你不要打电话来看你自己 – 它有一个你不应该颠覆的具体含义! 你可以做的重构,以达到相同的效果可能如下:
- (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。 但是你可以find解决方法,例如UINavigationController的委托方法,用于找出UIViewController在何时被呈现。 你可以使用这样的事情来跟踪已经呈现的最新的UIViewController。
更新
如果你在各个位上用适当的自动调整掩码来布局用户界面,有时你甚至不需要处理用户界面的“手动”布局,只需要处理…
在你的ViewController的viewDidLoad:
方法中使用通知中心来调用一个方法,然后在你的viewWillAppear:
方法中做你应该做的事情。 调用viewWillAppear:
直接不是一个好的select。
- (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"); }
迅速
更新了Swift 3
简短的回答
使用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 func willEnterForeground() { // do stuff }
长答案
要了解应用程序何时从后台返回,请使用NotificationCenter
观察器而不是viewWillAppear
。 这是一个示例项目,显示哪些事件发生时。 (这是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 func didBecomeActive() { print("did become active") } func willEnterForeground() { print("will enter foreground") } }
首先启动应用程序,输出顺序是:
view did load view will appear did become active view did appear
按下主页button,然后将应用程序返回到前台,输出顺序是:
will enter foreground did become active
所以,如果你最初试图使用viewWillAppear
然后UIApplicationWillEnterForeground
可能是你想要的。
viewWillAppear:animated:
在我看来,iOS SDK中最令人困惑的方法之一是在这样的情况下,即应用程序切换。 该方法只是根据视图控制器的视图和应用程序的窗口之间的关系来调用,即只有在视图出现在应用程序的窗口而不是屏幕上的时候才将消息发送给视图控制器。
当您的应用程序进入后台时,显然应用程序窗口的最顶层视图不再可见。 然而,在你的应用程序窗口的angular度来看,它们仍然是最顶层的视图,因此它们并没有从窗口中消失。 相反,这些意见消失了,因为应用程序窗口消失了。 他们没有消失,因为他们从窗口消失。
因此,当用户切换回您的应用程序,他们显然似乎出现在屏幕上,因为该窗口再次出现。 但从窗口的angular度来看,它们并没有消失。 因此,视图控制器永远不会得到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"); }