>source

뒤로 버튼(이전 화면으로 돌아가기, 부모 보기로 돌아가기) 버튼을 Navbar에서 눌렀을 때 몇 가지 작업을 수행해야 합니다.

이벤트를 포착하고 화면이 사라지기 전에 데이터를 일시 중지하고 저장하기 위해 일부 작업을 실행하기 위해 구현할 수 있는 방법이 있습니까?

탐색 컨트롤러의 뒤로 버튼에 대한 설정 작업의 중복 가능

nielsbot2021-09-19 19:25:58

이 스레드의 솔루션 보기

Jiri Volejnik2021-09-20 00:28:22

나는 이것을 이렇게 했다 여기에 결정을 보여라

Taras2021-09-20 05:59:34
  • 답변 # 1

    내가 사용한 페드로 마갈리에스다음과 같은 확장에서 사용할 때 navigationBar:shouldPop을 제외하고는 솔루션이 호출되지 않았습니다.

    extension UINavigationController: UINavigationBarDelegate {
     public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
          return self.topViewController?.navigationShouldPopOnBackButton() ?? true
    }
    

    그러나 UINavigationController 서브클래스에서 동일한 것이 잘 작동했습니다.

    class NavigationController: UINavigationController, UINavigationBarDelegate {
    func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
        return self.topViewController?.navigationShouldPopOnBackButton() ?? true
    }
    

    IOS 13에서 이 메서드가 호출되지 않고(그러나 다른 대리자 메서드는 예상대로 호출됨) 보고하는 몇 가지 다른 질문이 있습니다.?:

    iOS 13 및 UINavigationBarDelegate::shouldPop()

  • 답변 # 2

    이것이 작동하지 않는다고 주장하는 사람들은 잘못 알고 있습니다.

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if self.isMovingFromParent {
            print("we are being popped")
        }
    }
    

    잘 작동합니다. 그렇다면 그렇지 않다는 널리 퍼진 신화를 일으키는 원인은 무엇입니까?

    문제는 다른메소드의 잘못된 구현, 즉willMove(toParent:)전화하는 것을 잊었다감독자.

    구현하는 경우willMove(toParent:)부르지 않고감독자, 그 다음에self.isMovingFromParent될거야거짓의 사용viewWillDisappear실패로 보일 것입니다. 실패하지 않았습니다. 당신이 그것을 깨뜨렸다.

    참고:실제 문제는 일반적으로 첫 번째보기 컨트롤러가 팝되었음을 감지하는 두 번째보기 컨트롤러입니다. 여기에서 보다 일반적인 토론도 참조하십시오.

    편집주석은 이것이 수정되어야 한다고 제안합니다.viewDidDisappear보다는viewWillDisappear.

    이 code는 뒤로 버튼을 탭할 때 실행되지만 VC가 프로그래밍 방식으로 팝업되는 경우에도 실행됩니다.

    biomiker2021-09-20 02:37:58

    @bioomiker 물론이지만 다른 접근 방식에도 해당됩니다. 팝핑 팝핑입니다. 문제는 프로그래밍 방식으로 팝하지 않았을 때 팝을 감지하는 방법입니다. 프로그래밍 방식으로 팝하면 이미 터지는 것을 알고 있으므로 감지할 것이 없습니다.

    matt2021-09-20 02:37:58

    예, 이것은 다른 여러 접근 방식에 해당되며 많은 접근 방식이 비슷한 의견을 가지고 있습니다. 나는 이것이 특정한 반론이 있는 최근의 답변이었고 그것을 읽었을 때 희망을 얻었기 때문에 명확히 하고 있었습니다. 그러나 기록을 위해 문제는 뒤로 버튼을 누르는 것을 감지하는 방법입니다. 뒤로 버튼이 눌렸는지 여부를 나타내지 않고 뒤로 버튼을 누르지 않은 상황에서도 실행되는 code가 실제 질문을 완전히 해결하지 못한다고 말하는 것은 합리적인 주장입니다. 그 점에 대해 명백하다.

    biomiker2021-09-20 02:37:58

    불행히도 이것은 스와이프가 완전히 팝하지 않더라도 뷰 컨트롤러의 왼쪽 가장자리에서 대화형 스와이프 팝 제스처에 대해 true를 반환합니다. 따라서 willDisappear에서 확인하는 대신 didDisappear에서 확인하면 작동합니다.

    badhanganesh2021-09-20 10:47:34

    @badhanganesh 감사합니다. 해당 정보를 포함하도록 답변을 수정했습니다.

    matt2021-09-20 10:47:34
  • 답변 # 3

    동안viewWillAppear()그리고viewDidDisappear()뒤로 버튼을 탭할 때 호출되며 다른 시간에도 호출됩니다. 이에 대한 자세한 내용은 답변 끝을 참조하십시오.

    UIViewController.parent 사용

    뒤로 버튼 감지는 VC가 다음의 도움으로 부모(NavigationController)에서 제거될 때 더 잘 수행됩니다.willMoveToParentViewController(_:)또는didMoveToParentViewController()

    부모가 nil이면 뷰 컨트롤러가 탐색 스택에서 팝되고 닫힙니다. 부모가 nil이 아니면 스택에 추가되어 표시됩니다.

    //Objective-C
    -(void)willMoveToParentViewController:(UIViewController *)parent {
         [super willMoveToParentViewController:parent];
        if (!parent){
           //The back button was pressed or interactive gesture used
        }
    }
    //Swift
    override func willMove(toParent parent: UIViewController?) {
        super.willMove(toParent: parent)
        if parent== nil {
            //The back button was pressed or interactive gesture used
        }
    }
    

    교체윌무브~을위한했어뷰 컨트롤러가 해제된 작업을 수행하려면 self.parent를 확인하세요.

    해제 중지

    어떤 종류의 비동기 저장을 수행해야 하는 경우 상위 항목을 확인하면 전환을 "일시 중지"할 수 없습니다. 이를 위해 다음을 구현할 수 있습니다. 여기서 유일한 단점은 멋진 iOS 스타일/애니메이션 뒤로 버튼을 잃는 것입니다. 또한 대화형 스와이프 제스처에 주의하십시오. 이 경우를 처리하려면 다음을 사용하십시오.

    var backButton : UIBarButtonItem!
    override func viewDidLoad() {
        super.viewDidLoad()
         //Disable the swipe to make sure you get your chance to save
         self.navigationController?.interactivePopGestureRecognizer.enabled= false
         //Replace the default back button
        self.navigationItem.setHidesBackButton(true, animated: false)
        self.backButton= UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "goBack")
        self.navigationItem.leftBarButtonItem= backButton
    }
    //Then handle the button selection
    func goBack() {
        //Here we just remove the back button, you could also disabled it or better yet show an activityIndicator
        self.navigationItem.leftBarButtonItem= nil
        someData.saveInBackground { (success, error) -> Void in
            if success {
                self.navigationController?.popViewControllerAnimated(true)
                //Don't forget to re-enable the interactive gesture
                self.navigationController?.interactivePopGestureRecognizer.enabled= true
            }
            else {
                self.navigationItem.leftBarButtonItem= self.backButton
                //Handle the error
            }
        }
    }
    


    보기에 대한 추가 정보가 표시됩니다.

    못 받은 경우viewWill나타나다 viewDidDisappear문제, 예제를 통해 실행해 보겠습니다. 세 개의 뷰 컨트롤러가 있다고 가정합니다.

    1. ListVC: 사물에 대한 테이블 보기
    2. DetailVC: 사물에 대한 세부정보
    3. SettingsVC: 사물에 대한 몇 가지 옵션

    전화를 따르십시오.디테일VC당신이 에서 갈 때목록VC에게설정VC그리고 다시목록VC

    목록 > 세부 정보(디테일VC 푸시)Detail.viewDidAppear< -나타나다
    세부사항 > 설정(푸시 settingsVC)Detail.viewDidDisappear< -사라지다

    돌아가면...
    설정 > 세부정보(팝 설정VC)Detail.viewDidAppear< -나타나다
    세부사항 > 목록(팝 세부정보VC)Detail.viewDidDisappear< -사라지다

    참고viewDidDisappear뒤로 갈 때뿐만 아니라 앞으로 갈 때도 여러 번 호출됩니다. 빠른 작업을 원할 수 있지만 네트워크 호출과 같은 더 복잡한 작업을 저장하려면 그렇지 않을 수 있습니다.

    참고로 사용자 didMoveToParentViewController: 보기가 더 이상 표시되지 않을 때 작업을 수행합니다. 대화형 제스처로 iOS 7에 유용

    WCByrne2021-09-19 19:25:58

    didMoveToParentViewController* 오타가 있습니다

    thewormsterror2021-09-19 19:25:58
  • 답변 # 4

    다음과 같이 뒤로 버튼 콜백을 사용할 수 있습니다.

    -(BOOL) navigationShouldPopOnBackButton
    {
        [self backAction];
        return NO;
    }
    -(void) backAction {
        //your code goes here
        //show confirmation alert, for example
        //...
    }
    

    신속한 버전의 경우 전역 범위에서와 같이 할 수 있습니다.

    extension UIViewController {
         @objc func navigationShouldPopOnBackButton() -> Bool {
         return true
        }
    }
    extension UINavigationController: UINavigationBarDelegate {
         public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
              return self.topViewController?.navigationShouldPopOnBackButton() ?? true
        }
    }
    

    뒤로 버튼 동작을 제어하려는 뷰 컨트롤러에 다음을 입력합니다.

    override func navigationShouldPopOnBackButton() -> Bool {
        self.backAction()//Your action you want to perform.
        return true
    }
    

  • 답변 # 5

    업데이트:일부 의견에 따르면 원래 답변의 솔루션은 iOS 8+의 특정 시나리오에서 작동하지 않는 것 같습니다. 자세한 내용이 없으면 실제로 그런 것인지 확인할 수 없습니다.

    그런 상황에서 당신을 위해 대안이 있습니다. 재정의하여 뷰 컨트롤러가 팝업되는 시점을 감지하는 것이 가능합니다.willMove(toParentViewController:). 기본 아이디어는 다음과 같은 경우 뷰 컨트롤러가 팝업된다는 것입니다.부모의~이다.

    자세한 내용은 확인하십시오.


    iOS 5 이후로 이 상황을 처리하는 가장 쉬운 방법은 새로운 방법을 사용하는 것임을 알게 되었습니다.-(BOOL) isMovingFromParentViewController:

    -(void)viewWillDisappear:(BOOL)animated {
      [super viewWillDisappear:animated];
      if (self.isMovingFromParentViewController) {
        //Do your stuff here
      }
    }
    

    -(BOOL)isMovingFromParentViewController탐색 스택에서 컨트롤러를 푸시 및 팝할 때 의미가 있습니다.

    그러나 모달 뷰 컨트롤러를 제시하는 경우 다음을 사용해야 합니다.-(BOOL)이(가) 해고 중입니다.대신에:

    -(void)viewWillDisappear:(BOOL)animated {
      [super viewWillDisappear:animated];
      if (self.isBeingDismissed) {
        //Do your stuff here
      }
    }
    

    에 명시된 바와 같이 이 질문, 두 속성을 결합할 수 있습니다.

    -(void)viewWillDisappear:(BOOL)animated {
      [super viewWillDisappear:animated];
      if (self.isMovingFromParentViewController || self.isBeingDismissed) {
        //Do your stuff here
      }
    }
    

    다른 솔루션은UINavigationBar. 대신 내 접근 방식이 더 마음에 듭니다. 수행해야 할 작업을 이벤트를 트리거한 작업(예: 뒤로 버튼 누르기)과 분리하기 때문입니다.

  • 답변 # 6

    7ynk3r의 대답은 내가 결국 사용한 것과 정말 가까웠지만 약간의 조정이 필요했습니다.

    -(BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
        UIViewController *topViewController= self.topViewController;
        BOOL wasBackButtonClicked= topViewController.navigationItem== item;
        if (wasBackButtonClicked) {
            if ([topViewController respondsToSelector:@selector(navBackButtonPressed)]) {
                //if user did press back on the view controller where you handle the navBackButtonPressed
                [topViewController performSelector:@selector(navBackButtonPressed)];
                return NO;
            } else {
                //if user did press back but you are not on the view controller that can handle the navBackButtonPressed
                [self popViewControllerAnimated:YES];
                return YES;
            }
        } else {
            //when you call popViewController programmatically you do not want to pop it twice
            return YES;
        }
    }
    

  • 답변 # 7

    왼쪽의 NavigationBar에 UIControl을 추가하여 이 문제를 해결했습니다.

    UIControl *leftBarItemControl= [[UIControl alloc] initWithFrame:CGRectMake(0, 0, 90, 44)];
    [leftBarItemControl addTarget:self action:@selector(onLeftItemClick:) forControlEvents:UIControlEventTouchUpInside];
    self.leftItemControl= leftBarItemControl;
    [self.navigationController.navigationBar addSubview:leftBarItemControl];
    [self.navigationController.navigationBar bringSubviewToFront:leftBarItemControl];
    

    보기가 사라질 때 제거하는 것을 기억해야 합니다.

    -(void) viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
        if (self.leftItemControl) {
            [self.leftItemControl removeFromSuperview];
        }
    }
    

    그게 다야!

  • 답변 # 8

    Swift가 있는 iOS 9.3.x에서 작동합니다.

    override func didMoveToParentViewController(parent: UIViewController?) {
        super.didMoveToParentViewController(parent)
        if parent== self.navigationController?.parentViewController {
            print("Back tapped")
        }
    }
    

    여기에 있는 다른 솔루션과 달리 이것은 예기치 않게 트리거되지 않는 것 같습니다.

  • 답변 # 9

    UINavigationController가 있는 Swift의 경우:

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        if self.navigationController?.topViewController != self {
            print("back button tapped")
        }
    }
    

  • 답변 # 10

    self.navigationController.isMovingFromParentViewController가 iOS8 및 9에서 더 이상 작동하지 않습니다.

    -(void) viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
        if (self.navigationController.topViewController != self)
        {
            //Is Popping
        }
    }
    

  • 이전 JavaScript에서 객체를 배열로 안전하게 래핑하는 방법
  • 다음 java : 2개의 ArrayList 비교 및 ​​공통 요소 반환