今天在项目的开发中自定义了导航条的返回按钮,导致覆盖了系统的滑动返回功能,侧滑无法返回上一个界面,解决方法如下:
- 由于滑动返回是采用的收视识别,所以我们进入
UINavigationController
头文件搜索和手势有关的关键词,可以搜到@property(nullable, nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer
,然后我们在viewDidLoad中打印这个手势,发现手势没有被清空 - 既然手势没有被清空那么很可能就是这个手势的代理做了一些事情,导致手势失败,然后我们尝试清空代理:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@", self.interactivePopGestureRecognizer);
self.interactivePopGestureRecognizer.delegate = nil;
}
- 清空代理后确实可以实现滑动返回了,但是会有BUG,就是我们在跟控制器的时候也进行滑动,接下来就会造成程序假死,所以我们不能这么暴力的清空代理
- 我们应该把当前控制器设置为手势的代理,在代理方法中判断当前控制器是否是根控制器,如果是根控制器,则手势失效,如果非根控制器,则手势生效:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@", self.interactivePopGestureRecognizer);
self.interactivePopGestureRecognizer.delegate = self;
}
- 代理方法:
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return self.childViewControllers.count > 1;
}
- 到此BUG解决,手动设置滑动返回也实现了,大功告成!
!!!!!!!!!!!!!!!!!!但是,这还不能满足我们的需求,因为鄙人手指较短,喜欢滑动屏幕任何一个位置就返回上一个界面,嘿嘿,所以我们还要继续深入,实现全屏滑动返回:
- 先打印
NSLog(@"%@", self.interactivePopGestureRecognizer);
看看里面有什么信息:
<UIScreenEdgePanGestureRecognizer: 0x7f7f98c97430;
state = Possible; delaysTouchesBegan = YES;
view = <UILayoutContainerView 0x7f7f98f19d00>;
target= <(action=handleNavigationTransition:,
target=<_UINavigationInteractiveTransition 0x7f7f98c96ee0>)>
- 可以发现
self.interactivePopGestureRecognizer
的类型是UIScreenEdgePanGestureRecognizer
,我们可以跳进UIScreenEdgePanGestureRecognizer
头文件看看,发现里面有@property (readwrite, nonatomic, assign) UIRectEdge edges;
属性:
- 从这里我们可以猜一下(因为iOS开发中好多都是要靠猜的,嘿嘿),会不会是边距导致的不能全屏滑动,接下来我们就设置一下这个属性:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@", self.interactivePopGestureRecognizer);
UIScreenEdgePanGestureRecognizer *edgePan = (UIScreenEdgePanGestureRecognizer *)self.interactivePopGestureRecognizer;
edgePan.edges = UIRectEdgeNone;
self.interactivePopGestureRecognizer.delegate = self;
}
结果发现没有全屏滑动功能,而且连之前的边缘滑动效果也没有了,不顾不要气馁,总会有方法的,我们不妨换一种思路:有可能系统自带的手势根本就不支持全屏滑动返回,那么我们可不可以把系统的干掉,自己定义一个全屏滑动的手势呢?说干就干:
但是问题又来了,我们的target和action该怎么设置呢,大家有没有留意到我们之前打印的
NSLog(@"%@", self.interactivePopGestureRecognizer);
呢?其实里面显示的就是系统自带滑动返回的target(其实这个target就是self.interactivePopGestureRecognizer.delegate
)和action,我们可以巧妙的利用系统的方法(因为没门也不知道怎么做,嘿嘿),话不多少,上代码:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@", self.interactivePopGestureRecognizer.delegate);
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self.interactivePopGestureRecognizer.delegate action:@selector(handleNavigationTransition:)];
[self.view addGestureRecognizer:pan];
}
- 现在已经实现全屏返回功能,但是还有两点:
- 假死状态还会出现
- 系统的边缘滑动手势已经没用了,应该禁止
- 完善代码:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@", self.interactivePopGestureRecognizer.delegate);
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self.interactivePopGestureRecognizer.delegate action:@selector(handleNavigationTransition:)];
pan.delegate = self;
self.interactivePopGestureRecognizer.enabled = NO;
[self.view addGestureRecognizer:pan];
}
到此,滑动功能大功告成!