解决UIPageViewController与UITableViewCell左滑删除手势冲突

3,514 阅读2分钟

问题


在项目遇到了一个横向的 UIScrollView 嵌套两个 tableview,并且 right tableview 需要支持左滑删除 cell 的需求。

UI 布局后可以看到 cell 的左划删除不会被触发,仅仅只有在快速滑动才能进入编辑模式,因为的手势识别被 scrollview 阻挡了。

常规方案


找了一圈解决方案,大都是继承一个 UIScrollveiw,重写子类的

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
 if (gestureRecognizer.state != UIGestureRecognizerStatePossible) {
 return YES;
 } else {
 return NO;
 }
}

该方法 return YES可以让手势同时被 scrollview 和 tableview 识别。

不过因为项目中已经用到 了UIPageViewController,无法去继承一 个UIscrollView。 沿着这个思路走下去,定义一个 UIScrollView 子类,设置 pageViewController.scrollview.panGestureRecognizer.delegate = 子类。 重写子类的

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer

利用消息转发机制,将除此之外的子类其他方法转给原scrollview执行。 不过这个方法被 APPLE 否决了,APPLE 不允许我们修改 scrollview.panGestureRecognizer.delegate。

最终解决方案


最终解决方案是给 tableview 添加一个 gesture recognizer,

  1. 首先拿到 UIPageViewController 的 scrollview
UIScrollView *scrollView = nil;
    for (UIView *view in self.view.subviews) {
        if ([view isKindOfClass:[UIScrollView class]]) {
            scrollView = (UIScrollView *)view;
            break;
        }
    }
  1. 给 tableview 添加一个 panGestureRecognizer,设置手势响应优先级,当 tableview 响应手势时,scrollview 不响应手势
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:nil];
    panGesture.delaysTouchesBegan = YES;
    panGesture.cancelsTouchesInView = NO;
    panGesture.delegate = self;

    [self.tableView addGestureRecognizer:panGesture];
    self.scrollView.canCancelContentTouches = YES;
    [self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:panGesture];
  1. 实现代理方法

当 gesture recognizer 从 possible 状态转换为其他状态时,会调用此方法。

该方法 return NO 导致 gesture recognizer 进入 failed 状态手势不会再被识别。

当从右向左划删除cell的时候,translation.x是负值,所以当translation.x < 0时,给该方法 return YES 去继续识别 cell 左滑删除手势。若是从左往右滑,translation.x 为正值,该方法 return NO,tableveiw 的 gesture recognizer 进入 failed 状态,scrollview 会响应手势,滑动到 left tableview。

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if (![gestureRecognizer isMemberOfClass:[UIPanGestureRecognizer class]]) {
        return NO;
    }
    UIPanGestureRecognizer *panGesture = (UIPanGestureRecognizer *)gestureRecognizer;
    CGPoint translation = [panGesture translationInView:self.tableView];
    return translation.x < 0;
}

return YES 允许 tableview 和 scrollview 同时识别手势

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
    shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return otherGestureRecognizer.view == self.tableView;
}