Попытка обработать действие кнопки "назад" в iOS
Мне нужно определить, когда пользователь нажимает кнопку "назад" на панели навигации, чтобы выполнять некоторые операции, когда это происходит. Я пытаюсь вручную установить действие на такую кнопку:
[self.navigationItem.backBarButtonItem setAction:@selector(performBackNavigation:)];
- (void)performBackNavigation:(id)sender
{
// Do operations
[self.navigationController popViewControllerAnimated:NO];
}
Я сначала поместил этот код в сам контроллер представления, но обнаружил, что self.navigationItem.backBarButtonItem
, казалось, был nil
, поэтому я переместил этот же код в родительский контроллер представления, который подталкивает его в стек навигации. Но я не могу заставить его работать. Я прочитал несколько сообщений по этой проблеме, и некоторые из них сказали, что селектор должен быть установлен в родительском контроллере представления, но для меня это все равно не работает... Что я могу сделать неправильно?
Спасибо
Ответы
Ответ 1
Попробуйте использовать этот код с помощью метода VIewWillDisappear
для обнаружения нажатия кнопки "Назад" в NavigationItem:
-(void) viewWillDisappear:(BOOL)animated
{
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound)
{
// Navigation button was pressed. Do some stuff
[self.navigationController popViewControllerAnimated:NO];
}
[super viewWillDisappear:animated];
}
ИЛИ Существует другой способ получить действие кнопки "Навигация" BAck.
Создать пользовательскую кнопку для кнопки UINavigationItem для возврата.
Для Ex:
В ViewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:@"Home" style:UIBarButtonItemStyleBordered target:self action:@selector(home:)];
self.navigationItem.leftBarButtonItem=newBackButton;
}
-(void)home:(UIBarButtonItem *)sender
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
Swift:
override func willMoveToParentViewController(parent: UIViewController?)
{
if parent == nil
{
// Back btn Event handler
}
}
Ответ 2
Swift
override func didMoveToParentViewController(parent: UIViewController?) {
if parent == nil {
//"Back pressed"
}
}
Ответ 3
Возможно, эти ответы не соответствуют вашему объяснению, но заголовок вопроса. Это полезно, когда вы пытаетесь узнать, когда вы нажали кнопку "Назад" на UINavigationBar
.
В этом случае вы можете использовать протокол UINavigationBarDelegate
и реализовать один из следующих способов:
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item;
Когда вызывается метод didPopItem
, потому что вы либо нажали кнопку "Назад", либо вы использовали метод [UINavigationBar popNavigationItemAnimated:]
, и панель навигации всплыла.
Теперь, если вы хотите узнать, какое действие вызвало метод didPopItem
, вы можете использовать флаг.
При таком подходе мне не нужно вручную добавлять элемент с левой кнопкой мыши со стрелочным изображением, чтобы сделать его похожим на кнопку возврата iOS и иметь возможность устанавливать мои пользовательские цели/действия.
Посмотрим на пример:
У меня есть контроллер представлений, у которого есть контроллер просмотра страниц и пользовательский просмотр индикатора страницы. Я также использую пользовательский UINavigationBar, чтобы отобразить заголовок, чтобы узнать, на какой странице я и кнопка "Назад", чтобы вернуться на предыдущую страницу. И я также могу перейти на предыдущую/следующую страницу на странице контроллера.
#pragma mark - UIPageViewController Delegate Methods
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
if( completed ) {
//...
if( currentIndex > lastIndex ) {
UINavigationItem *navigationItem = [[UINavigationItem alloc] initWithTitle:@"Some page title"];
[[_someViewController navigationBar] pushNavigationItem:navigationItem animated:YES];
[[_someViewController pageControl] setCurrentPage:currentIndex];
} else {
_autoPop = YES; //We pop the item automatically from code.
[[_someViewController navigationBar] popNavigationItemAnimated:YES];
[[_someViewController pageControl] setCurrentPage:currentIndex];
}
}
}
Итак, я реализую методы делегатов UINavigationBar:
#pragma mark - UINavigationBar Delegate Methods
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
if( !_autoPop ) {
//Pop by back button tap
} else {
//Pop from code
}
_autoPop = NO;
return YES;
}
В этом случае я использовал shouldPopItem
, потому что поп-анимирован, и я хотел сразу обращаться к кнопке "Назад" и не ждать завершения перехода.
Ответ 4
Проблема с didMoveToParentViewController
, которую он вызывает, после того, как родительский вид будет полностью виден, поэтому, если вам нужно выполнить некоторые задачи до этого, это не сработает.
И это не работает с движением жесты анимации.
Использование willMoveToParentViewController
работает лучше.
Objective-c
- (void)willMoveToParentViewController:(UIViewController *)parent{
if (parent == NULL) {
// ...
}
}
Swift
override func willMoveToParentViewController(parent: UIViewController?) {
if parent == nil {
// ...
}
}
Ответ 5
Это Objective-C версия dadachi's Ответ:
Objective-C
- (void)didMoveToParentViewController:(UIViewController *)parent{
if (parent == NULL) {
NSLog(@"Back Pressed");
}
}
Ответ 6
Установите делегат UINavigationBar, а затем используйте:
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
//handle the action here
}
Ответ 7
Установите UINavigationControllerDelegate и реализуйте эту функцию делегата (Swift):
func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
if viewController is <target class> {
//if the only way to get back - back button was pressed
}
}
Ответ 8
Ни один из других решений не работал для меня, но это делает:
Создайте свой собственный подкласс UINavigationController, внесите его в UINavigationBarDelegate (нет необходимости вручную устанавливать делегат панели навигации), добавьте расширение UIViewController, которое определяет метод, который будет вызываться при нажатии кнопки "Назад", а затем реализовать этот метод в вашем подклассе UINavigationController:
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
self.topViewController?.methodToBeCalledOnBackButtonPress()
self.popViewController(animated: true)
return true
}
Ответ 9
Используйте пользовательский подкласс UINavigationController
, который реализует метод shouldPop
.
В Свифте:
class NavigationController: UINavigationController, UINavigationBarDelegate
{
var shouldPopHandler: (() -> Bool)?
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool
{
if let shouldPopHandler = self.shouldPopHandler, !shouldPopHandler()
{
return false
}
self.popViewController(animated: true) // Needed!
return true
}
}
Когда установлено, должен быть вызван shouldPopHandler()
, чтобы решить, будет ли контроллер всплывающим или нет. Когда он не установлен, он просто выскочит как обычно.
Это хорошая идея, чтобы отключить UINavigationController
interactivePopGestureRecognizer
как в противном случае жест не вызовет ваш обработчик.
Ответ 10
В Swift 4 или выше:
override func didMove(toParent parent: UIViewController?) {
if parent == nil {
//"Back pressed"
}
}