обратный вызов кнопки Назад в navigationController в iOS
Я нажал вид на навигационный контроллер, и когда я нажимаю кнопку "назад", он автоматически переходит к предыдущему виду. Я хочу сделать несколько вещей, когда кнопка "Назад" нажата, прежде чем выскакивать из стека. Какая функция обратного вызова кнопки "Назад"?
11 ответов
Уильяма Джокуша ответ решить эту проблему с помощью простого трюка.
-(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];
}
на мой взгляд лучшее решение.
- (void)didMoveToParentViewController:(UIViewController *)parent
{
if (![parent isEqual:self.parentViewController]) {
NSLog(@"Back pressed");
}
}
но он работает только с iOS5+
вероятно, лучше переопределить backbutton, чтобы вы могли обрабатывать событие до вид выскочил для таких вещей, как подтверждение пользователя.
в viewDidLoad создайте UIBarButtonItem и установите self.navigationItem.leftBarButtonItem к ней, проходящего в сельсовет
- (void) viewDidLoad
{
// change the back button to cancel and add an event handler
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@”back”
style:UIBarButtonItemStyleBordered
target:self
action:@selector(handleBack:)];
self.navigationItem.leftBarButtonItem = backButton;
[backButton release];
}
- (void) handleBack:(id)sender
{
// pop to root view controller
[self.navigationController popToRootViewControllerAnimated:YES];
}
затем вы можете сделать такие вещи, как поднять UIAlertView для подтверждения действия, затем поп-контроллер вида и т. д.
или вместо создания новой кнопки backbutton, вы можете соответствует методам делегирования UINavigationController для выполнения действий при нажатии кнопки "Назад".
Я заканчиваю с этим решением. Когда мы нажимаем кнопку Назад, вызывается метод viewDidDisappear. мы можем проверить, вызвав селектор ismovingfromparentviewcontroller, который возвращает true. мы можем передавать данные обратно (используя Delegate).надеюсь, это поможет кому-то.
-(void)viewDidDisappear:(BOOL)animated{
if (self.isMovingToParentViewController) {
}
if (self.isMovingFromParentViewController) {
//moving back
//pass to viewCollection delegate and update UI
[self.delegateObject passBackSavedData:self.dataModel];
}
}
для "BEFORE popping The view off the stack":
- (void)willMoveToParentViewController:(UIViewController *)parent{
if (parent == nil){
NSLog(@"do whatever you want here");
}
}
есть более подходящий способ, чем спрашивать viewControllers. Вы можете сделать свой контроллер делегатом панели навигации с кнопкой "Назад". Вот пример. В реализации контроллера, где вы хотите обработать нажатие кнопки "Назад", сообщите ему, что он будет реализовывать протокол UINavigationBarDelegate:
@interface MyViewController () <UINavigationBarDelegate>
затем где-то в вашем коде инициализации (возможно, в viewDidLoad) сделайте свой контроллер делегатом своей навигации бар:
self.navigationController.navigationBar.delegate = self;
наконец, реализуйте метод shouldPopItem. Этот метод вызывается при нажатии кнопки "Назад". Если у вас есть несколько контроллеров или навигационных элементов в стеке, вы, вероятно, захотите проверить, какие из этих навигационных элементов выталкиваются (параметр item), так что вы только делаете свои пользовательские вещи, когда ожидаете. Вот пример:
-(BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
NSLog(@"Back button got pressed!");
//if you return NO, the back button press is cancelled
return YES;
}
это правильный способ обнаружить это.
- (void)willMoveToParentViewController:(UIViewController *)parent{
if (parent == nil){
//do stuff
}
}
этот метод вызывается при нажатии view. Таким образом, проверка parent==nil предназначена для выскакивания контроллера вида из стека
Если вы не можете использовать "viewWillDisappear" или аналогичный метод, попробуйте подкласс UINavigationController. Это класс заголовка:
#import <Foundation/Foundation.h>
@class MyViewController;
@interface CCNavigationController : UINavigationController
@property (nonatomic, strong) MyViewController *viewController;
@end
класс реализации:
#import "CCNavigationController.h"
#import "MyViewController.h"
@implementation CCNavigationController {
}
- (UIViewController *)popViewControllerAnimated:(BOOL)animated {
@"This is the moment for you to do whatever you want"
[self.viewController doCustomMethod];
return [super popViewControllerAnimated:animated];
}
@end
С другой стороны, вам нужно связать этот viewController с вашим пользовательским NavigationController, поэтому в вашем методе viewDidLoad для вашего обычного viewController сделайте следующее:
@implementation MyViewController {
- (void)viewDidLoad
{
[super viewDidLoad];
((CCNavigationController*)self.navigationController).viewController = self;
}
}
вот еще один способ, который я реализовал (не тестировал его с помощью unwind segue, но, вероятно, он не отличался бы, поскольку другие заявили в отношении других решений на этой странице), чтобы контроллер родительского вида выполнял действия до того, как дочерний VC, который он нажал, выскочил из стека представления (я использовал это на пару уровней ниже исходного UINavigationController). Это также может быть использовано для выполнения действий до того, как childVC будет вытеснен. Это имеет дополнительное преимущество работы с помощью кнопки возврата системы iOS вместо создания пользовательского UIBarButtonItem или UIButton.
-
у вашего родителя VC принять
UINavigationControllerDelegate
протокол и регистрация для сообщений делегата:MyParentViewController : UIViewController <UINavigationControllerDelegate> -(void)viewDidLoad { self.navigationcontroller.delegate = self; }
-
реализовать этот
UINavigationControllerDelegate
метод экземпляра вMyParentViewController
:- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { // Test if operation is a pop; can also test for a push (i.e., do something before the ChildVC is pushed if (operation == UINavigationControllerOperationPop) { // Make sure it's the child class you're looking for if ([fromVC isKindOfClass:[ChildViewController class]]) { // Can handle logic here or send to another method; can also access all properties of child VC at this time return [self didPressBackButtonOnChildViewControllerVC:fromVC]; } } // If you don't want to specify a nav controller transition return nil; }
-
если вы укажете конкретную функцию обратного вызова в приведенном выше
UINavigationControllerDelegate
экземпляр метод-(id <UIViewControllerAnimatedTransitioning>)didPressBackButtonOnAddSearchRegionsVC:(UIViewController *)fromVC { ChildViewController *childVC = ChildViewController.new; childVC = (ChildViewController *)fromVC; // childVC.propertiesIWantToAccess go here // If you don't want to specify a nav controller transition return nil;
}
Если вы используете раскадровку, и вы исходите из Push segue, вы также можете просто переопределить shouldPerformSegueWithIdentifier:sender:
.
Это то, что он работает для меня в Swift:
override func viewWillDisappear(_ animated: Bool) {
if self.navigationController?.viewControllers.index(of: self) == nil {
// back button pressed or back gesture performed
}
super.viewWillDisappear(animated)
}