developer tip

UIViewController가 탐색 스택에서 Popped를 가져 오는지 확인하고 있습니까?

optionbox 2020. 12. 14. 08:06
반응형

UIViewController가 탐색 스택에서 Popped를 가져 오는지 확인하고 있습니까?


작업을 수행 할 수 있도록 뷰 컨트롤러가 내비게이션 스택에서 터질 때를 알아야합니다.

-viewWillDisappear를 사용할 수 없습니다. 왜냐하면 뷰 컨트롤러가 어떤 이유로 든 화면 밖으로 이동할 때 호출되기 때문입니다 (새 뷰 컨트롤러가 맨 위에 눌려지는 것과 같이).

특히 컨트롤러가 저절로 터질 때를 알아야합니다.

미리 감사드립니다.


이에 대한 명시적인 메시지가 있다고 생각하지 않지만 UINavigationController를 하위 클래스 화하고 popViewControllerAnimated를 재정의 할 수 있습니다 (내가 시도해 본 적이 없음).

또는 뷰 컨트롤러에 대한 다른 참조가없는 경우-dealloc에 ​​추가 할 수 있습니까?


viewWillDisappear제시된 VC에서 메서드를 재정의 한 다음 isMovingFromParentViewController재정의 내에서 플래그 를 확인하고 특정 논리를 수행합니다. 제 경우에는 탐색 컨트롤러 도구 모음을 숨기고 있습니다. 제시된 VC가 완벽하지는 않지만 밀려났다는 것을 이해해야합니다.


의 사용자 정의 하위 클래스에서 willMoveToParentViewController:(대신 viewWillDisappear:) 재정의 해보 십시오 UIViewController.

뷰 컨트롤러가 컨테이너 뷰 컨트롤러에서 추가되거나 제거되기 직전에 호출됩니다.

- (void)willMoveToParentViewController:(UIViewController *)parent
{
    [super willMoveToParentViewController:parent];
    if (!parent) {
        // `self` is about to get popped.
    }
}

다행히도 viewWillDisappear 메서드가 호출 될 즈음에는 viewController가 이미 스택에서 제거 되었기 때문에 viewController가 더 이상 self.navigationController.viewControllers 에 없기 때문에 팝업되는 것을 알 수 있습니다.

스위프트 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!");
    }
}

이것은 나를 위해 일하고 있습니다.

- (void)viewDidDisappear:(BOOL)animated
{
    if (self.parentViewController == nil) {
        NSLog(@"viewDidDisappear doesn't have parent so it's been popped");
        //release stuff here
    } else {
        NSLog(@"PersonViewController view just hidden");
    }
}

여기서 잡을 수 있습니다.

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {

    if (viewController == YourAboutToAppearController) {
            // do something
    }
}

이것은 새로운 뷰가 표시되기 직전에 실행됩니다. 아직 아무도 움직이지 않았습니다. 나는 asinine NavigationController 앞에서 마술을하기 위해 항상 사용합니다. 제목과 버튼 제목을 설정하고 거기에서 무엇이든 할 수 있습니다.


나도 같은 문제를 안고있어. 나는 viewDisdisappear로 시도했지만 함수가 호출되지 않았습니다. (아마도 모든 VC가 UITableViewController이기 때문에 이유를 모르겠습니다.) Alex의 제안은 잘 작동하지만 탐색 컨트롤러가 아래에 표시되면 실패합니다. 더 많은 탭.이 경우 내비게이션 컨트롤러의 모든 VC에는 하위 클래스로 분류 한 내비게이션 컨트롤러가 아닌 UIMoreNavigationController로 navigationController가 있으므로 VC가 터질 때 nav에서 알림을받지 못합니다.
마침내 문제를 해결했습니다. UINavigationController 범주로 다시 작성하십시오-(UIViewController *) popViewControllerAnimated : (BOOL) animated

- (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


나는 이것을 시도했다 :

- (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];
}

아이디어는 팝업시 뷰 컨트롤러의 navigationController가 nil로 설정된다는 것입니다. 따라서 뷰가 사라지고 더 이상 navigationController가 있으면 팝업되었다고 결론을 내 렸습니다. (다른 시나리오에서는 작동하지 않을 수 있습니다).

viewWillDisappear가 문서에서 언급되지 않았기 때문에 팝업시 호출된다는 것을 보증 할 수 없습니다. 나는보기가 평면도 일 때, 그리고 평면도 아래에서 그것을 시도했습니다.

행운을 빕니다, 오데드.


하위 클래스 UINavigationController및 재정의 popViewController:

스위프트 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
    }

}

이것을 사용할 수 있습니다.

if(self.isMovingToParentViewController)
{
    NSLog(@"Pushed");
}
else
{
    NSLog(@"Popped");
}

UINavigationBarDelegate의 navigationBar : shouldPopItem 프로토콜 메서드를 사용할 수 있습니다.


([self.navigationController.viewControllers indexOfObject : self] == NSNotFound) {//이 뷰가 터진 경우 viewwilldisappear에서이 확인을 시도합니다. }


알림을 관찰 할 수 있습니다.

- (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
    }
}

I needed to also prevent from popping sometimes so the best answer for me was written by Orkhan Alikhanov. But it did not work because the delegate was not set, so I made the final version:

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

I have added viewControllers.count == 1 case, because if there is one controller in the stack and user makes the gesture, it will freeze the UI of your application.

참고URL : https://stackoverflow.com/questions/642312/checking-if-a-uiviewcontroller-is-about-to-get-popped-from-a-navigation-stack

반응형