Как отловить нажатие кнопки «Назад» в UINavigationController и выполнить свой код?
Решение через делегат UINavigationController
Самый правильный способ — подписаться на протокол UINavigationControllerDelegate и реализовать метод navigationController(_:willShow:animated:). Этот метод вызывается перед каждым показом контроллера, и вы можете проверить, является ли исчезающий контроллер вашим.
Вот пошаговая инструкция:
- Сделайте ваш контроллер делегатом навигационного контроллера (лучше в
viewDidLoad). - Реализуйте метод
navigationController(_:willShow:animated:). - Внутри метода проверьте, исчезает ли ваш контроллер (т.е. новый контроллер не равен текущему).
- Выполните нужное действие.
Пример кода:
class SecondViewController: UIViewController, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Устанавливаем делегат
navigationController?.delegate = self
}
// UINavigationControllerDelegate
func navigationController(_ navigationController: UINavigationController,
willShow viewController: UIViewController,
animated: Bool) {
// Проверяем, что мы уходим с текущего экрана
guard viewController != self else { return }
// Если новый контроллер не равен self — значит, мы нажали "Назад"
// или произошёл pop-переход
print("Пользователь нажал кнопку «Назад»!")
// Здесь ваш код: сохранение данных, показ алерта и т.д.
}
}
Важно: Этот метод вызывается для любого pop-перехода, включая swipe-жест назад. Если вам нужно отличить именно кнопку «Назад» от свайпа, используйте дополнительную проверку свойства isMovingFromParent или isBeingDismissed.
Более точный вариант с проверкой:
func navigationController(_ navigationController: UINavigationController,
willShow viewController: UIViewController,
animated: Bool) {
guard viewController != self else { return }
// Проверяем, что контроллер действительно уходит из стека
if self.isMovingFromParent {
print("Нажата кнопка «Назад» или сделан свайп назад")
// Ваш код
}
}
Альтернатива: кастомная кнопка «Назад» с сохранением стиля
Если вам нужно полностью контролировать поведение (например, показывать алерт перед уходом), можно заменить стандартную кнопку на свою, но сохранить её внешний вид:
override func viewDidLoad() {
super.viewDidLoad()
// Создаём кастомную кнопку с системным изображением
let backButton = UIBarButtonItem(
image: UIImage(systemName: "chevron.left"),
style: .plain,
target: self,
action: #selector(backButtonTapped)
)
navigationItem.leftBarButtonItem = backButton
}
@objc func backButtonTapped() {
// Ваше действие
print("Кастомная кнопка «Назад» нажата")
// Возвращаемся назад
navigationController?.popViewController(animated: true)
}
Этот способ даёт полный контроль, но теряется стандартная анимация перехода (если не использовать popViewController).
Использование свойства isMovingFromParent
Более простой и лаконичный подход — переопределить метод viewWillDisappear с проверкой свойства isMovingFromParent. Это свойство возвращает true, если контроллер удаляется из стека навигации (т.е. происходит именно pop-переход, а не push).
Пример:
class SecondViewController: UIViewController {
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isMovingFromParent {
// Пользователь нажал «Назад» или сделал свайп
print("Выполняем действие при уходе с экрана")
// Сохраняем данные, отправляем аналитику и т.д.
}
}
}
Плюсы:
- Минимум кода — не нужно реализовывать делегат.
- Работает как для кнопки «Назад», так и для свайп-жеста.
- Не ломает стандартное поведение навигации.
Минусы:
- Не позволяет предотвратить уход с экрана (например, показать алерт с подтверждением). Для этого нужно использовать
navigationController(_:shouldPop:)или кастомную кнопку. - Вызывается также при программном pop-переходе (через
popViewController).
Этот метод идеален, если вам нужно просто выполнить действие при уходе (например, сохранить черновик), без блокировки навигации.
Ответов пока нет.
Войдите чтобы оставить ответ