检测导航栏上按下“后退”button的时间
在导航栏上按下后退button(返回到前一个屏幕,返回到父视图)时,我需要执行一些操作。
是否有一些方法可以实现捕捉事件并启动一些操作,以在屏幕消失之前暂停和保存数据?
自iOS 5以来,我发现处理这种情况的最简单方法是使用新方法- (BOOL)isMovingFromParentViewController
:
- (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (self.isMovingFromParentViewController) { // Do your stuff here } }
- (BOOL)isMovingFromParentViewController
是有道理的,当你推动和popup导航堆栈中的控制器。
但是,如果你正在展示模态视图控制器,你应该使用- (BOOL)isBeingDismissed
来代替:
- (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (self.isBeingDismissed) { // Do your stuff here } }
正如在这个问题中所指出的,你可以结合这两个属性:
- (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (self.isMovingFromParentViewController || self.isBeingDismissed) { // Do your stuff here } }
其他解决scheme依赖于UINavigationBar
的存在。 我更喜欢这种方法,因为它将所需的任务从触发事件的操作中解耦出来,即按下后退button。
虽然viewWillAppear()
和viewDidDisappear()
在点击后退button时被调用,但是在其他时候也会调用它们。 查看更多答案的结尾。
父视图控制器
当使用willMoveToParentViewController(_:)
或者didMoveToParentViewController()
将VC从父级(NavigationController)中移除时,检测后退button会更好。
如果父母为零,则视图控制器正从导航堆栈popup并被解散。 如果父母不是零,则将其添加到堆栈并呈现。
// Objective-C -(void)willMoveToParentViewController:(UIViewController *)parent { [super willMoveToParentViewController:parent]; if (!parent){ // The back button was pressed or interactive gesture used } } // Swift override func willMove(toParentViewController parent: UIViewController?) { super.willMove(toParentViewController:parent) if parent == nil { // The back button was pressed or interactive gesture used } }
在视图控制器被解散后,将交换为willMove
for didMove
并检查self.parent以执行工作。
停止解雇(asynchronous)
请注意,如果您需要执行某种asynchronous保存,检查父代不允许您“暂停”转换。 要做到这一点,你可以实现以下内容。 唯一的缺点是你失去了花哨的iOS风格/animation后退button。 在这里也要小心交互式滑动手势。 使用以下来处理这种情况。
var backButton : UIBarButtonItem! override func viewDidLoad() { super.viewDidLoad() // Disable the swipe to make sure you get your chance to save self.navigationController?.interactivePopGestureRecognizer.enabled = false // Replace the default back button self.navigationItem.setHidesBackButton(true, animated: false) self.backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "goBack") self.navigationItem.leftBarButtonItem = backButton } // Then handle the button selection func goBack() { // Here we just remove the back button, you could also disabled it or better yet show an activityIndicator self.navigationItem.leftBarButtonItem = nil someData.saveInBackground { (success, error) -> Void in if success { self.navigationController?.popViewControllerAnimated(true) // Don't forget to re-enable the interactive gesture self.navigationController?.interactivePopGestureRecognizer.enabled = true } else { self.navigationItem.leftBarButtonItem = self.backButton // Handle the error } } }
会出现更多/将会出现
如果你没有得到viewWillAppear
viewDidDisappear
问题,让我们通过一个例子。 假设你有三个视图控制器:
- ListVC: 事物的表格视图
- DetailVC: 关于事物的细节
- SettingsVC: 一些东西的选项
当你从listVC
到settingsVC
并返回到listVC
让我们按照detailVC
上的调用
列表>细节 (push detailVC) Detail.viewDidAppear
< – 出现
细节>设置 (推送设置Detail.viewDidDisappear
) Detail.viewDidDisappear
< – 消失
而当我们回去…
设置>细节 (popup设置Detail.viewDidAppear
) Detail.viewDidAppear
< – 出现
Detail> List (pop detailVC) Detail.viewDidDisappear
< – 消失
请注意, viewDidDisappear
被多次viewDidDisappear
,不仅在返回时,还在向前时。 对于一个可能需要的快速操作,但对于一个更复杂的操作,如networking调用来保存,它可能不会。
第一种方法
- (void)didMoveToParentViewController:(UIViewController *)parent { if (![parent isEqual:self.parentViewController]) { NSLog(@"Back pressed"); } }
第二种方法
-(void) viewWillDisappear:(BOOL)animated { if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) { // back button was pressed. We know this is true because self is no longer // in the navigation stack. } [super viewWillDisappear:animated]; }
我已经打了两天这个问题了(或者说打架)。 IMO最好的办法就是创build一个扩展类和一个协议,像这样:
@protocol UINavigationControllerBackButtonDelegate <NSObject> /** * Indicates that the back button was pressed. * If this message is implemented the pop logic must be manually handled. */ - (void)backButtonPressed; @end @interface UINavigationController(BackButtonHandler) @end @implementation UINavigationController(BackButtonHandler) - (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item { UIViewController *topViewController = self.topViewController; BOOL wasBackButtonClicked = topViewController.navigationItem == item; SEL backButtonPressedSel = @selector(backButtonPressed); if (wasBackButtonClicked && [topViewController respondsToSelector:backButtonPressedSel]) { [topViewController performSelector:backButtonPressedSel]; return NO; } else { [self popViewControllerAnimated:YES]; return YES; } } @end
这是有效的,因为UINavigationController
将接收到对navigationBar:shouldPopItem:
的调用navigationBar:shouldPopItem:
每当视图控制器被popup时。 在那里,我们检测是否按下了(任何其他button)。 你唯一需要做的是在视图控制器里按下后面的地方实现协议。
记得手动popup视图控制器里面backButtonPressedSel
,如果一切正常。
如果你已经有了子类UINavigationViewController
并且实现了navigationBar:shouldPopItem:
不用担心,这不会干扰它。
您可能也有兴趣禁用后面的手势。
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.navigationController.interactivePopGestureRecognizer.enabled = NO; }
这在Swift中适用于iOS 9.3.x:
override func didMoveToParentViewController(parent: UIViewController?) { super.didMoveToParentViewController(parent) if parent == self.navigationController?.parentViewController { print("Back tapped") } }
不同于这里的其他解决scheme,这似乎并不意外触发。
为了logging,我认为这是他正在寻找的更多…
UIBarButtonItem *l_backButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRewind target:self action:@selector(backToRootView:)]; self.navigationItem.leftBarButtonItem = l_backButton; - (void) backToRootView:(id)sender { // Perform some custom code [self.navigationController popToRootViewControllerAnimated:YES]; }
正如purrrminator
所说, purrrminator
的回答并不完全正确,因为即使以编程方式popup控制器,也会执行your stuff
。
我迄今为止find的解决scheme并不是很好,但是对我来说很有用。 除了elitalon
说的,我也检查我是否以编程方式popup:
- (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if ((self.isMovingFromParentViewController || self.isBeingDismissed) && !self.isPoppingProgrammatically) { // Do your stuff here } }
您必须将该属性添加到您的控制器,并在以编程方式popup之前将其设置为YES:
self.isPoppingProgrammatically = YES; [self.navigationController popViewControllerAnimated:YES];
谢谢你的帮助!
最好的方法是使用UINavigationController委托方法
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
使用这个你可以知道什么控制器显示UINavigationController。
if ([viewController isKindOfClass:[HomeController class]]) { NSLog(@"Show home controller"); }
对于使用UINavigationController的Swift:
override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) if self.navigationController?.topViewController != self { print("back button tapped") } }
7ynk3r的答案非常接近我最终使用的内容,但是它需要一些调整:
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item { UIViewController *topViewController = self.topViewController; BOOL wasBackButtonClicked = topViewController.navigationItem == item; if (wasBackButtonClicked) { if ([topViewController respondsToSelector:@selector(navBackButtonPressed)]) { // if user did press back on the view controller where you handle the navBackButtonPressed [topViewController performSelector:@selector(navBackButtonPressed)]; return NO; } else { // if user did press back but you are not on the view controller that can handle the navBackButtonPressed [self popViewControllerAnimated:YES]; return YES; } } else { // when you call popViewController programmatically you do not want to pop it twice return YES; } }
你应该看看UINavigationBarDelegate协议 。 在这种情况下,您可能需要使用navigationBar:shouldPopItem:方法。
正如Coli88所说,你应该检查UINavigationBarDelegate协议。
更一般的方式,当当前可见的视图控制器保留的视图即将消失时,也可以使用- (void)viewWillDisapear:(BOOL)animated
来执行自定义工作。 不幸的是,这将包括打扰推动和stream行的情况。
我已经解决了这个问题,通过添加一个UIControl左侧的导航栏。
UIControl *leftBarItemControl = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, 90, 44)]; [leftBarItemControl addTarget:self action:@selector(onLeftItemClick:) forControlEvents:UIControlEventTouchUpInside]; self.leftItemControl = leftBarItemControl; [self.navigationController.navigationBar addSubview:leftBarItemControl]; [self.navigationController.navigationBar bringSubviewToFront:leftBarItemControl];
你需要记住当视图消失时将其删除:
- (void) viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (self.leftItemControl) { [self.leftItemControl removeFromSuperview]; } }
就这样!
您可以使用后退buttoncallback,如下所示:
- (BOOL) navigationShouldPopOnBackButton { [self backAction]; return NO; } - (void) backAction { // your code goes here // show confirmation alert, for example // ... }
self.navigationController.isMovingFromParentViewController无法在iOS8和9上使用:
-(void) viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (self.navigationController.topViewController != self) { // Is Popping } }
(迅速)
finalyfind解决scheme..我们正在寻找的方法是“willShowViewController”这是UINavigationController的委托方法
//IMPORT UINavigationControllerDelegate !! class PushedController: UIViewController, UINavigationControllerDelegate { override func viewDidLoad() { //set delegate to current class (self) navigationController?.delegate = self } func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) { //MyViewController shoud be the name of your parent Class if var myViewController = viewController as? MyViewController { //YOUR STUFF } } }