手动实现滑动返回功能

今天在项目的开发中自定义了导航条的返回按钮,导致覆盖了系统的滑动返回功能,侧滑无法返回上一个界面,解决方法如下:
  • 由于滑动返回是采用的收视识别,所以我们进入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];
    
}

到此,滑动功能大功告成!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容