链接:http://pan.baidu.com/s/1nvzrBfj
.h
#import <UIKit/UIKit.h>
@interface UINavigationController (XYFullscreenPopGesture)
@end
@interface UIViewController (XYFullscreenPopGesture)
/**
* 是否隐藏导航栏
*/
@property (nonatomic, assign) BOOL xy_prefersNavigationBarHidden;
/**
* 手势是否禁用
*/
@property (nonatomic, assign) BOOL xy_interactivePopDisabled;
@end
.m
#import "UINavigationController+XYFullscreenPopGesture.h"
#import <objc/runtime.h>
//手势代理实现
@interface _XYFullscreenPopGestureRecognizerDelegate : NSObject <UIGestureRecognizerDelegate>
@property (nonatomic, weak) UINavigationController *navigationController;
@end
@implementation _XYFullscreenPopGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer{
//只有一个视图控制器时,返回NO
if (self.navigationController.viewControllers.count <= 1) {
return NO;
}
//手势禁用时,返回NO
UIViewController *topViewController = self.navigationController.viewControllers.lastObject;
if (topViewController.xy_interactivePopDisabled) {
return NO;
}
//正在执行手势,时返回NO
if ([[self.navigationController valueForKey:@"_isTransitioning"] boolValue]) {
return NO;
}
//手势相反时,返回NO
CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view];
if (translation.x <= 0) {
return NO;
}
return YES;
}
@end
typedef void (^_XYViewControllerWillAppearInjectBlock)(UIViewController *viewController, BOOL animated);
@interface UIViewController (XYFullscreenPopGesturePrivate)
@property (nonatomic, copy) _XYViewControllerWillAppearInjectBlock xy_willAppearInjectBlock;
@end
@implementation UIViewController (XYFullscreenPopGesturePrivate)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(viewWillAppear:);
SEL swizzledSelector = @selector(xy_viewWillAppear:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (success) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
//将要消失的时候
- (void)xy_viewWillAppear:(BOOL)animated{
[self xy_viewWillAppear:animated];
if (self.xy_willAppearInjectBlock) {
self.xy_willAppearInjectBlock(self,animated);
}
}
//消失回调block
- (_XYViewControllerWillAppearInjectBlock)xy_willAppearInjectBlock{
return objc_getAssociatedObject(self, _cmd);
}
- (void)setXy_willAppearInjectBlock:(_XYViewControllerWillAppearInjectBlock)xy_willAppearInjectBlock{
objc_setAssociatedObject(self, @selector(xy_willAppearInjectBlock), xy_willAppearInjectBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
@end
@implementation UINavigationController (XYFullscreenPopGesture)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class aClass = [self class];
SEL originalSelector = @selector(pushViewController:animated:);
SEL swizzledSelector = @selector(xy_pushViewController:animated:);
Method originalMethod = class_getInstanceMethod(aClass, originalSelector);
Method swizzledMethod = class_getInstanceMethod(aClass, swizzledSelector);
BOOL success =
class_addMethod(aClass,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (success) {
class_replaceMethod(aClass,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
- (void)xy_pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
if (![self.interactivePopGestureRecognizer.view.gestureRecognizers containsObject:self.xy_fullscreenPopGestureRecognizer]) {
//不包含手势时,添加手势
[self.interactivePopGestureRecognizer.view addGestureRecognizer:self.xy_fullscreenPopGestureRecognizer];
/**
* 获取系统手势的target数组
*/
NSArray* _targets = [self.interactivePopGestureRecognizer valueForKey:@"targets"];
/**
* 获取它的唯一对象,我们知道它是一个叫UIGestureRecognizerTarget的私有类,它有一个属性叫_target
*/
id gestureRecognizerTarget = [_targets firstObject];
/**
* 获取_target:_UINavigationInteractiveTransition,它有一个方法叫handleNavigationTransition:
*/
id internalTarget = [gestureRecognizerTarget valueForKey:@"target"];
/**
* 通过前面的打印,我们从控制台获取出来它的方法签名。
*/
SEL internalAction = NSSelectorFromString(@"handleNavigationTransition:");
/**
* 创建一个与系统一模一样的手势,我们只把它的类改为UIPanGestureRecognizer
*/
self.xy_fullscreenPopGestureRecognizer.delegate = self.xy_popGestureRecognizerDelegate;
[self.xy_fullscreenPopGestureRecognizer addTarget:internalTarget action:internalAction];
//禁用系统手势
self.interactivePopGestureRecognizer.enabled = NO;
}
[self xy_setupViewControllerBasedNavigationBarAppearanceIfNeeded:viewController];
//调用pushViewController:animated:
if (![self.viewControllers containsObject:viewController]) {
[self xy_pushViewController:viewController animated:animated];
}
}
- (void)xy_setupViewControllerBasedNavigationBarAppearanceIfNeeded:(UIViewController *)appearingViewController{
//设置
__weak typeof(self) weakSelf = self;
_XYViewControllerWillAppearInjectBlock block = ^(UIViewController* viewController,BOOL animated){
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf setNavigationBarHidden:viewController.xy_prefersNavigationBarHidden animated:animated];
}
};
appearingViewController.xy_willAppearInjectBlock = block;
UIViewController *disappearingViewController = self.viewControllers.lastObject;
if (disappearingViewController && !disappearingViewController.xy_willAppearInjectBlock) {
disappearingViewController.xy_willAppearInjectBlock = block;
}
}
//关联手势
- (UIPanGestureRecognizer *)xy_fullscreenPopGestureRecognizer
{
UIPanGestureRecognizer *panGestureRecognizer = objc_getAssociatedObject(self, _cmd);
if (!panGestureRecognizer) {
panGestureRecognizer = [[UIPanGestureRecognizer alloc] init];
panGestureRecognizer.maximumNumberOfTouches = 1;
objc_setAssociatedObject(self, _cmd, panGestureRecognizer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return panGestureRecognizer;
}
- (_XYFullscreenPopGestureRecognizerDelegate *)xy_popGestureRecognizerDelegate{
_XYFullscreenPopGestureRecognizerDelegate* delegate = objc_getAssociatedObject(self, _cmd);
if (!delegate) {
delegate = [[_XYFullscreenPopGestureRecognizerDelegate alloc]init];
delegate.navigationController = self;
objc_setAssociatedObject(self, _cmd, delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return delegate;
}
@end
@implementation UIViewController (XYFullscreenPopGesture)
//是否隐藏导航栏
- (BOOL)xy_prefersNavigationBarHidden{
return objc_getAssociatedObject(self, _cmd);
}
- (void)setXy_prefersNavigationBarHidden:(BOOL)xy_prefersNavigationBarHidden{
objc_setAssociatedObject(self, @selector(xy_prefersNavigationBarHidden), @(xy_prefersNavigationBarHidden), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
//手势是否禁用
- (BOOL)xy_interactivePopDisabled{
return [objc_getAssociatedObject(self, _cmd) boolValue];
}
- (void)setXy_interactivePopDisabled:(BOOL)xy_interactivePopDisabled{
objc_setAssociatedObject(self, @selector(xy_interactivePopDisabled), @(xy_interactivePopDisabled), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end