Проверка того, собирается ли UIViewController выходить из стека навигации?
Мне нужно знать, когда мой диспетчер представлений собирается выскочить из штабеля nav, чтобы я мог выполнить действие.
Я не могу использовать -viewWillDisappear, потому что он вызывается, когда контроллер просмотра перемещается за экран по какой-либо причине (например, если новый контроллер отображения нажат вверх).
Мне нужно знать, когда сам контроллер будет выгружаться.
Любые идеи были бы удивительными, спасибо заранее.
Ответы
Ответ 1
Я не думаю, что для этого есть явное сообщение, но вы можете подклассифицировать UINavigationController и переопределить - popViewControllerAnimated (хотя я не пробовал это до себя).
В качестве альтернативы, если нет других ссылок на контроллер вида, можете ли вы добавить его в dealloc?
Ответ 2
Переопределите метод viewWillDisappear
в представленном VC, затем проверьте флаг isMovingFromParentViewController
в пределах переопределения и выполните определенную логику. В моем случае я скрываю панель инструментов навигационных контроллеров. Все еще требует, чтобы ваш представленный VC понял, что он был нажат, хотя и не идеально.
Ответ 3
Попробуйте переопределить willMoveToParentViewController:
(вместо viewWillDisappear:
) в вашем пользовательском подклассе UIViewController
.
Вызывается непосредственно перед добавлением или удалением контроллера вида из контроллера представления контейнера.
- (void)willMoveToParentViewController:(UIViewController *)parent
{
[super willMoveToParentViewController:parent];
if (!parent) {
// `self` is about to get popped.
}
}
Ответ 4
К счастью, к тому времени, когда вызывается метод viewWillDisappear, viewController уже удален из стека, поэтому мы знаем, что viewController выталкивает, потому что его больше нет в self.navigationController.viewControllers.
Swift 4
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let nav = self.navigationController {
let isPopping = !nav.viewControllers.contains(self)
if isPopping {
// popping off nav
} else {
// on nav, not popping off (pushing past, being presented over, etc.)
}
} else {
// not on nav at all
}
}
Оригинальный код
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if ((self.navigationController) &&
(![self.navigationController.viewControllers containsObject:self])) {
NSLog(@"I've been popped!");
}
}
Ответ 5
Это работает для меня.
- (void)viewDidDisappear:(BOOL)animated
{
if (self.parentViewController == nil) {
NSLog(@"viewDidDisappear doesn't have parent so it been popped");
//release stuff here
} else {
NSLog(@"PersonViewController view just hidden");
}
}
Ответ 6
Вы можете поймать его здесь.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (viewController == YourAboutToAppearController) {
// do something
}
}
Это будет срабатывать непосредственно перед отображением нового представления. Никто еще не двигался. Я использую все время, чтобы делать магию перед asinine NavigationController. Вы можете устанавливать заголовки и названия кнопок и делать что угодно.
Ответ 7
У меня та же проблема. Я попытался с viewDisDisappear, но у меня нет функции get called:( (не знаю, почему, может быть, потому, что все мои VC - UITableViewController).
Предложение Alex работает нормально, но оно не работает, если ваш навигационный контроллер отображается на вкладке "Дополнительно". В этом случае все контроллеры ваших навигационных контроллеров имеют navigationController как UIMoreNavigationController, а не контроллер навигации, который вы подклассифицировали, поэтому вы не будете уведомлены навигатором, когда VC вот-вот выскочит.
Наконец, я решил проблему с категорией UINavigationController, просто переписываю - (UIViewController *) popViewControllerAnimated: (BOOL) анимированный
- (UIViewController *)popViewControllerAnimated:(BOOL)animated{
NSLog(@"UINavigationController(Magic)");
UIViewController *vc = self.topViewController;
if ([vc respondsToSelector:@selector(viewControllerWillBePopped)]) {
[vc performSelector:@selector(viewControllerWillBePopped)];
}
NSArray *vcs = self.viewControllers;
UIViewController *vcc = [vcs objectAtIndex:[vcs count] - 2];
[self popToViewController:vcc animated:YES];
return vcc;}
Это хорошо работает для меня: D
Ответ 8
Я пробовал это:
- (void) viewWillDisappear:(BOOL)animated {
// If we are disappearing because we were removed from navigation stack
if (self.navigationController == nil) {
// YOUR CODE HERE
}
[super viewWillDisappear:animated];
}
Идея состоит в том, что при вызове контроллера навигации viewController установлено значение nil.
Поэтому, если представление должно исчезнуть, и у него больше есть navigationController, я пришел к выводу, что он был выбит. (может не работать в других сценариях).
Нельзя ручаться, что viewWillDisappear будет вызван при появлении, так как он не упоминается в документах. Я попробовал это, когда вид был сверху, и ниже верхнего вида - и он работал в обоих.
Удачи,
Одед.
Ответ 9
Подкласс UINavigationController
и переопределить popViewController
:
Swift 3
protocol CanPreventPopProtocol {
func shouldBePopped() -> Bool
}
class MyNavigationController: UINavigationController {
override func popViewController(animated: Bool) -> UIViewController? {
let viewController = self.topViewController
if let canPreventPop = viewController as? CanPreventPopProtocol {
if !canPreventPop.shouldBePopped() {
return nil
}
}
return super.popViewController(animated: animated)
}
//important to prevent UI thread from freezing
//
//if popViewController is called by gesture recognizer and prevented by returning nil
//UI will freeze after calling super.popViewController
//so that, in order to solve the problem we should not return nil from popViewController
//we interrupt the call made by gesture recognizer to popViewController through
//returning false on gestureRecognizerShouldBegin
//
//tested on iOS 9.3.2 not others
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
let viewController = self.topViewController
if let canPreventPop = viewController as? CanPreventPopProtocol {
if !canPreventPop.shouldBePopped() {
return false
}
}
return true
}
}
Ответ 10
Вы можете использовать этот:
if(self.isMovingToParentViewController)
{
NSLog(@"Pushed");
}
else
{
NSLog(@"Popped");
}
Ответ 11
Возможно, вы могли бы использовать метод UINavigationBarDelegate navigationBar: shouldPopItem.
Ответ 12
Попробуйте сделать эту проверку в viewwilldisappear
if ([self.navigationController.viewControllers indexOfObject: self] == NSNotFound) {
// Появление этого представления произошло.
}
Ответ 13
Мне также нужно было иногда не давать совать, поэтому лучший ответ для меня написал Орхан Алиханов. Но это не сработало, потому что делегат не был установлен, поэтому я сделал окончательный вариант:
import UIKit
class CustomActionsNavigationController: UINavigationController,
UIGestureRecognizerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
interactivePopGestureRecognizer?.delegate = self
}
override func popViewController(animated: Bool) -> UIViewController? {
if let delegate = topViewController as? CustomActionsNavigationControllerDelegate {
guard delegate.shouldPop() else { return nil }
}
return super.popViewController(animated: animated)
}
// important to prevent UI thread from freezing
//
// if popViewController is called by gesture recognizer and prevented by returning nil
// UI will freeze after calling super.popViewController
// so that, in order to solve the problem we should not return nil from popViewController
// we interrupt the call made by gesture recognizer to popViewController through
// returning false on gestureRecognizerShouldBegin
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if let delegate = topViewController as? CustomActionsNavigationControllerDelegate {
if !delegate.shouldPop() {
return false
}
}
// This if statement prevents navigation controller to pop when there is only one view controller
if viewControllers.count == 1 {
return false
}
return true
}
}
protocol CustomActionsNavigationControllerDelegate {
func shouldPop() -> Bool
}
UPDATE
Я добавил случай viewControllers.count == 1
, потому что, если в стеке один контроллер и пользователь делает жест, он замораживает пользовательский интерфейс вашего приложения.
Ответ 14
Вы можете наблюдать уведомление:
- (void)viewDidLoad{
[super viewDidLoad];
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(navigationControllerWillShowViewController:) name:@"UINavigationControllerWillShowViewControllerNotification" object:nil];
}
- (void)navigationControllerDidShowViewController:(NSNotification *)notification{
UIViewController *lastVisible = notification.userInfo[@"UINavigationControllerLastVisibleViewController"];
if(lastVisible == self){
// we are being popped
}
}