[ios] popViewController의 완료 블록

를 사용하여 모달 뷰 컨트롤러를 닫을 때 dismissViewController완료 블록을 제공하는 옵션이 있습니다. 에 대해 비슷한 것이 popViewController있습니까?

완료 인수는 매우 편리합니다. 예를 들어, 모달이 화면에서 벗어날 때까지 테이블 뷰에서 행 제거를 보류하여 사용자가 행 애니메이션을 볼 수 있도록 할 수 있습니다. 푸시 뷰 컨트롤러에서 돌아올 때도 같은 기회를 원합니다.

내가 배치를 시도 popViewControllerUIView나는 완료 블록에 액세스 할 수 있습니까 애니메이션 블록. 그러나 이로 인해 팝업되는 뷰에 원치 않는 부작용이 발생합니다.

이러한 방법을 사용할 수없는 경우 몇 가지 해결 방법은 무엇입니까?



답변

2 년 전에 답변이 받아 들여진 것을 알고 있지만이 답변은 불완전합니다.

원하는 것을 즉시 수행 할 수있는 방법은 없습니다.

이는 UINavigationControllerAPI가 이에 대한 옵션을 제공하지 않기 때문에 기술적으로 정확 합니다. 그러나 CoreAnimation 프레임 워크를 사용하면 기본 애니메이션에 완료 블록을 추가 할 수 있습니다.

[CATransaction begin];
[CATransaction setCompletionBlock:^{
    // handle completion here
}];

[self.navigationController popViewControllerAnimated:YES];

[CATransaction commit];

완료 블록은에 의해 사용 된 애니메이션이 popViewControllerAnimated:종료 되는 즉시 호출됩니다 . 이 기능은 iOS 4부터 사용할 수 있습니다.


답변

들어 iOS9 SWIFT 버전 – (이전 버전에 대한 테스트를하지 않은) 매력처럼 작동합니다. 이 답변을 바탕으로

extension UINavigationController {    
    func pushViewController(viewController: UIViewController, animated: Bool, completion: () -> ()) {
        pushViewController(viewController, animated: animated)

        if let coordinator = transitionCoordinator() where animated {
            coordinator.animateAlongsideTransition(nil) { _ in
                completion()
            }
        } else {
            completion()
        }
    }

    func popViewController(animated: Bool, completion: () -> ()) {
        popViewControllerAnimated(animated)

        if let coordinator = transitionCoordinator() where animated {
            coordinator.animateAlongsideTransition(nil) { _ in
                completion()
            }
        } else {
            completion()
        }
    }
}


답변

@JorisKluivers 답변 Swift으로 확장 버전을 만들었습니다 .

push및에 대해 애니메이션이 완료된 후 완료 클로저를 호출합니다 pop.

extension UINavigationController {
    func popViewControllerWithHandler(completion: ()->()) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        self.popViewControllerAnimated(true)
        CATransaction.commit()
    }
    func pushViewController(viewController: UIViewController, completion: ()->()) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        self.pushViewController(viewController, animated: true)
        CATransaction.commit()
    }
}


답변

SWIFT 4.1

extension UINavigationController {
func pushToViewController(_ viewController: UIViewController, animated:Bool = true, completion: @escaping ()->()) {
    CATransaction.begin()
    CATransaction.setCompletionBlock(completion)
    self.pushViewController(viewController, animated: animated)
    CATransaction.commit()
}

func popViewController(animated:Bool = true, completion: @escaping ()->()) {
    CATransaction.begin()
    CATransaction.setCompletionBlock(completion)
    self.popViewController(animated: animated)
    CATransaction.commit()
}

func popToViewController(_ viewController: UIViewController, animated:Bool = true, completion: @escaping ()->()) {
    CATransaction.begin()
    CATransaction.setCompletionBlock(completion)
    self.popToViewController(viewController, animated: animated)
    CATransaction.commit()
}

func popToRootViewController(animated:Bool = true, completion: @escaping ()->()) {
    CATransaction.begin()
    CATransaction.setCompletionBlock(completion)
    self.popToRootViewController(animated: animated)
    CATransaction.commit()
}
}


답변

나는 같은 문제가 있었다. 그리고 여러 차례에 걸쳐 완료 블록 체인 내에서 사용해야했기 때문에 UINavigationController 하위 클래스에서이 일반 솔루션을 만들었습니다.

- (void) navigationController:(UINavigationController *) navigationController didShowViewController:(UIViewController *) viewController animated:(BOOL) animated {
    if (_completion) {
        dispatch_async(dispatch_get_main_queue(),
        ^{
            _completion();
            _completion = nil;
         });
    }
}

- (UIViewController *) popViewControllerAnimated:(BOOL) animated completion:(void (^)()) completion {
    _completion = completion;
    return [super popViewControllerAnimated:animated];
}

가정

@interface NavigationController : UINavigationController <UINavigationControllerDelegate>

@implementation NavigationController {
    void (^_completion)();
}

- (id) initWithRootViewController:(UIViewController *) rootViewController {
    self = [super initWithRootViewController:rootViewController];
    if (self) {
        self.delegate = self;
    }
    return self;
}


답변

원하는 것을 즉시 수행 할 수있는 방법은 없습니다. 즉, 탐색 스택에서 뷰 컨트롤러를 팝업하는 완료 블록이있는 메서드가 없습니다.

내가 할 일은 논리를 viewDidAppear. 뷰가 화면에 표시되면 호출됩니다. 뷰 컨트롤러가 나타나는 모든 다른 시나리오에 대해 호출되지만 괜찮습니다.

또는이 UINavigationControllerDelegate방법 navigationController:didShowViewController:animated:을 사용하여 비슷한 작업을 수행 할 수 있습니다 . 내비게이션 컨트롤러가 뷰 컨트롤러를 밀거나 터 뜨렸을 때 호출됩니다.


답변

애니메이션을 올바르게 사용하거나 사용하지 않고 popToRootViewController다음 을 포함합니다 .

 // updated for Swift 3.0
extension UINavigationController {

  private func doAfterAnimatingTransition(animated: Bool, completion: @escaping (() -> Void)) {
    if let coordinator = transitionCoordinator, animated {
      coordinator.animate(alongsideTransition: nil, completion: { _ in
        completion()
      })
    } else {
      DispatchQueue.main.async {
        completion()
      }
    }
  }

  func pushViewController(viewController: UIViewController, animated: Bool, completion: @escaping (() ->     Void)) {
    pushViewController(viewController, animated: animated)
    doAfterAnimatingTransition(animated: animated, completion: completion)
  }

  func popViewController(animated: Bool, completion: @escaping (() -> Void)) {
    popViewController(animated: animated)
    doAfterAnimatingTransition(animated: animated, completion: completion)
  }

  func popToRootViewController(animated: Bool, completion: @escaping (() -> Void)) {
    popToRootViewController(animated: animated)
    doAfterAnimatingTransition(animated: animated, completion: completion)
  }
}