UINavigationController "pushViewController : animated"에 대한 완료 처리기?
UINavigationController
다음 뷰 컨트롤러 를 표시하기 위해를 사용하여 앱을 만드는 중 입니다. iOS5에는 새로운 프레젠테이션 방법이 있습니다 UIViewControllers
.
presentViewController:animated:completion:
이제 완료 처리기가없는 이유를 묻습니다 UINavigationController
. 그냥
pushViewController:animated:
새로운 것과 같은 내 자신의 완료 처리기를 만들 수 presentViewController:animated:completion:
있습니까?
다른 최신 솔루션에 대한 par의 답변 참조
UINavigationController
애니메이션은로 실행 CoreAnimation
되므로 코드를 캡슐화하여 CATransaction
완료 블록을 설정하는 것이 좋습니다.
스위프트 :
신속하게 확장 기능을 만드는 것이 좋습니다.
extension UINavigationController {
public func pushViewController(viewController: UIViewController,
animated: Bool,
completion: @escaping (() -> Void)?) {
CATransaction.begin()
CATransaction.setCompletionBlock(completion)
pushViewController(viewController, animated: animated)
CATransaction.commit()
}
}
용법:
navigationController?.pushViewController(vc, animated: true) {
// Animation done
}
목표 -C
헤더:
#import <UIKit/UIKit.h>
@interface UINavigationController (CompletionHandler)
- (void)completionhandler_pushViewController:(UIViewController *)viewController
animated:(BOOL)animated
completion:(void (^)(void))completion;
@end
이행:
#import "UINavigationController+CompletionHandler.h"
#import <QuartzCore/QuartzCore.h>
@implementation UINavigationController (CompletionHandler)
- (void)completionhandler_pushViewController:(UIViewController *)viewController
animated:(BOOL)animated
completion:(void (^)(void))completion
{
[CATransaction begin];
[CATransaction setCompletionBlock:completion];
[self pushViewController:viewController animated:animated];
[CATransaction commit];
}
@end
iOS 7 이상 Swift
스위프트 4 :
// 2018.10.30 par:
// I've updated this answer with an asynchronous dispatch to the main queue
// when we're called without animation. This really should have been in the
// previous solutions I gave but I forgot to add it.
extension UINavigationController {
public func pushViewController(
_ viewController: UIViewController,
animated: Bool,
completion: @escaping () -> Void)
{
pushViewController(viewController, animated: animated)
guard animated, let coordinator = transitionCoordinator else {
DispatchQueue.main.async { completion() }
return
}
coordinator.animate(alongsideTransition: nil) { _ in completion() }
}
func popViewController(
animated: Bool,
completion: @escaping () -> Void)
{
popViewController(animated: animated)
guard animated, let coordinator = transitionCoordinator else {
DispatchQueue.main.async { completion() }
return
}
coordinator.animate(alongsideTransition: nil) { _ in completion() }
}
}
편집 : 원래 답변의 Swift 3 버전을 추가했습니다. 이 버전에서는 많은 사람들을 혼란스럽게하는 것처럼 보이기 때문에 Swift 2 버전에 표시된 예제 공동 애니메이션을 제거했습니다.
스위프트 3 :
import UIKit
// Swift 3 version, no co-animation (alongsideTransition parameter is nil)
extension UINavigationController {
public func pushViewController(
_ viewController: UIViewController,
animated: Bool,
completion: @escaping (Void) -> Void)
{
pushViewController(viewController, animated: animated)
guard animated, let coordinator = transitionCoordinator else {
completion()
return
}
coordinator.animate(alongsideTransition: nil) { _ in completion() }
}
}
스위프트 2 :
import UIKit
// Swift 2 Version, shows example co-animation (status bar update)
extension UINavigationController {
public func pushViewController(
viewController: UIViewController,
animated: Bool,
completion: Void -> Void)
{
pushViewController(viewController, animated: animated)
guard animated, let coordinator = transitionCoordinator() else {
completion()
return
}
coordinator.animateAlongsideTransition(
// pass nil here or do something animated if you'd like, e.g.:
{ context in
viewController.setNeedsStatusBarAppearanceUpdate()
},
completion: { context in
completion()
}
)
}
}
를 기반으로 파의 대답은 하지만, 간단하고와 (유일한 iOS9 함께 작업 한이었다)는 다른 실종 (절대 호출되지중인 완료 주도 할 수있는) :
extension UINavigationController {
func pushViewController(_ viewController: UIViewController, animated: Bool, completion: @escaping () -> Void) {
pushViewController(viewController, animated: animated)
if animated, let coordinator = transitionCoordinator {
coordinator.animate(alongsideTransition: nil) { _ in
completion()
}
} else {
completion()
}
}
func popViewController(animated: Bool, completion: @escaping () -> Void) {
popViewController(animated: animated)
if animated, let coordinator = transitionCoordinator {
coordinator.animate(alongsideTransition: nil) { _ in
completion()
}
} else {
completion()
}
}
}
현재는 UINavigationController
이를 지원하지 않습니다. 그러나 UINavigationControllerDelegate
사용할 수있는 것이 있습니다.
이를 수행하는 쉬운 방법 UINavigationController
은 완료 블록 속성 을 서브 클래 싱 하고 추가하는 것입니다.
@interface PbNavigationController : UINavigationController <UINavigationControllerDelegate>
@property (nonatomic,copy) dispatch_block_t completionBlock;
@end
@implementation PbNavigationController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.delegate = self;
}
return self;
}
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
NSLog(@"didShowViewController:%@", viewController);
if (self.completionBlock) {
self.completionBlock();
self.completionBlock = nil;
}
}
@end
새 뷰 컨트롤러를 푸시하기 전에 완료 블록을 설정해야합니다.
UIViewController *vc = ...;
((PbNavigationController *)self.navigationController).completionBlock = ^ {
NSLog(@"COMPLETED");
};
[self.navigationController pushViewController:vc animated:YES];
이 새 하위 클래스는 Interface Builder에서 할당하거나 다음과 같이 프로그래밍 방식으로 사용할 수 있습니다.
PbNavigationController *nc = [[PbNavigationController alloc]initWithRootViewController:yourRootViewController];
To expand on @Klaas' answer (and as a result of this question) I've added completion blocks directly to the push method:
@interface PbNavigationController : UINavigationController <UINavigationControllerDelegate>
@property (nonatomic,copy) dispatch_block_t completionBlock;
@property (nonatomic,strong) UIViewController * pushedVC;
@end
@implementation PbNavigationController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.delegate = self;
}
return self;
}
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
NSLog(@"didShowViewController:%@", viewController);
if (self.completionBlock && self.pushedVC == viewController) {
self.completionBlock();
}
self.completionBlock = nil;
self.pushedVC = nil;
}
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (self.pushedVC != viewController) {
self.pushedVC = nil;
self.completionBlock = nil;
}
}
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated completion:(dispatch_block_t)completion {
self.pushedVC = viewController;
self.completionBlock = completion;
[self pushViewController:viewController animated:animated];
}
@end
To be used as follows:
UIViewController *vc = ...;
[(PbNavigationController *)self.navigationController pushViewController:vc animated:YES completion:^ {
NSLog(@"COMPLETED");
}];
Since iOS 7.0,you can use UIViewControllerTransitionCoordinator
to add a push completion block:
UINavigationController *nav = self.navigationController;
[nav pushViewController:vc animated:YES];
id<UIViewControllerTransitionCoordinator> coordinator = vc.transitionCoordinator;
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
} completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
NSLog(@"push completed");
}];
Here is the Swift 4 version with the Pop.
extension UINavigationController {
public func pushViewController(viewController: UIViewController,
animated: Bool,
completion: (() -> Void)?) {
CATransaction.begin()
CATransaction.setCompletionBlock(completion)
pushViewController(viewController, animated: animated)
CATransaction.commit()
}
public func popViewController(animated: Bool,
completion: (() -> Void)?) {
CATransaction.begin()
CATransaction.setCompletionBlock(completion)
popViewController(animated: animated)
CATransaction.commit()
}
}
Just in case someone else needs this.
Swift 2.0
extension UINavigationController : UINavigationControllerDelegate {
private struct AssociatedKeys {
static var currentCompletioObjectHandle = "currentCompletioObjectHandle"
}
typealias Completion = @convention(block) (UIViewController)->()
var completionBlock:Completion?{
get{
let chBlock = unsafeBitCast(objc_getAssociatedObject(self, &AssociatedKeys.currentCompletioObjectHandle), Completion.self)
return chBlock as Completion
}set{
if let newValue = newValue {
let newValueObj : AnyObject = unsafeBitCast(newValue, AnyObject.self)
objc_setAssociatedObject(self, &AssociatedKeys.currentCompletioObjectHandle, newValueObj, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
func popToViewController(animated: Bool,comp:Completion){
if (self.delegate == nil){
self.delegate = self
}
completionBlock = comp
self.popViewControllerAnimated(true)
}
func pushViewController(viewController: UIViewController, comp:Completion) {
if (self.delegate == nil){
self.delegate = self
}
completionBlock = comp
self.pushViewController(viewController, animated: true)
}
public func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool){
if let comp = completionBlock{
comp(viewController)
completionBlock = nil
self.delegate = nil
}
}
}
It takes a little more pipework to add this behavior and retain the ability to set an external delegate.
Here's a documented implementation that maintains delegate functionality:
'code' 카테고리의 다른 글
PostgreSQL LIKE 쿼리 성능 변화 (0) | 2020.08.17 |
---|---|
점 표기법 문자열을 사용하여 개체 자식 속성에 액세스 (0) | 2020.08.17 |
Android 조각에서 getIntent (). getExtras ()는 어디서 / 어떻게합니까? (0) | 2020.08.17 |
동일한 onclick에서 두 함수 호출 (0) | 2020.08.17 |
Robolectric에서 애플리케이션의 컨텍스트에 어떻게 액세스 할 수 있습니까? (0) | 2020.08.17 |