对之前一直写一直用的功能,来做个总结。
系统自带的pop效果是轻扫左边边缘pop返回,要实现的效果是轻扫全屏pop返回。
思路
要改变系统的效果,1.重写,2.设置系统提供的相关属性(直接设置/通过KVC)
探究
首先,我们先去UINavigationController.h源文件中找系统提供的方法或者属性。@property(nullable, nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;
,interactivePopGestureRecognizer是只读属性,属于UIGestureRecognizer这个类。因为是readonly的,所以我们无法重写和自定义,继续点进去UIGestureRecognizer.h查看,有一个enabled属性,所以可以将enabled设置为NO,或者猜测是否有私有属性可以通过KVC搞定的。
于是,log一下interactivePopGestureRecognizer一看究竟
NSLog(@"%@",self.navigationController.interactivePopGestureRecognizer);
打印结果
; target= <(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fd9a16003c0>)>>
通过log,interactivePopGestureRecognizer属性其实是UIScreenEdgePanGestureRecognizer类,查看UIScreenEdgePanGestureRecognizer.h源文件,继承自UIPanGestureRecognizer,包含一个属性edges,也就是所有边缘,从这个枚举看出都是设置边缘的,无法修改edges为全部
typedef NS_OPTIONS(NSUInteger, UIRectEdge) {
UIRectEdgeNone = 0,
UIRectEdgeTop = 1 << 0,
UIRectEdgeLeft = 1 << 1,
UIRectEdgeBottom = 1 << 2,
UIRectEdgeRight = 1 << 3,
UIRectEdgeAll = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight
} NS_ENUM_AVAILABLE_IOS(7_0);
所以,我们要做的是,创建一个UIPanGestureRecognizer手势,让它的target和action执行系统响应的方法,所以可以用runtime获取系统手势的target和action
unsigned int count = 0;
Ivar *var = class_copyIvarList([UIGestureRecognizer class], &count);
for (int i = 0; i < count; i++) {
Ivar _var = *(var + i);
NSLog(@"%s ------ %s",ivar_getName(_var),ivar_getTypeEncoding(_var));
}
接下来,可以通过KVC获取_targets了
NSMutableArray *targets = [self.navigationController.interactivePopGestureRecognizer valueForKeyPath:@"_targets"];
NSLog(@"%@",targets);
/*
(
"(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fdbf2e02110>)"
)
*/
_targets数组中就一个元素,虽然不知道什么类型,可以选择用 id 接收。如果想继续探究,那就打断点看下控制台,isa指向UIGestureRecognizerTarget私有类。
代码
我们可以在自定义的NavigationController中添加以下代码
@interface SSNavigationController ()
@end
@implementation SSNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
[self initGlobalPan];
}
-(void)initGlobalPan
{
//取消系统自带手势
self.interactivePopGestureRecognizer.enabled = NO;
//获取系统的手势的target数组
NSMutableArray *_targets = [self.interactivePopGestureRecognizer valueForKeyPath:@"_targets"];
//获取target
id target = [[_targets firstObject] valueForKeyPath:@"_target"];
//获取action
SEL action = NSSelectorFromString(@"handleNavigationTransition:");
//创建一个与系统一样的手势 只把它的类改为UIPanGestureRecognizer
UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget: target action: action];
popRecognizer.delegate = self;
//添加到系统手势作用的view上
UIView *gestureView = self.interactivePopGestureRecognizer.view;
[gestureView addGestureRecognizer:popRecognizer];
}
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
//当前控制器为根控制器,pop动画正在执行的时候不允许手势
return self.viewControllers.count != 1 && ![[self valueForKeyPath:@"_isTransitioning"] boolValue];
}
@end