如何判断 UIPageViewController 翻页是由于 swipe/pan 还是点击

How to tell whether a UIPageViewController page turn is due to a swipe/pan or a tap

使用 UIPageViewController 时,用户可以向右或向左滑动以创建跟随手指的动画翻页。或者用户只需点击页面视图的一侧或另一侧即可翻页。当翻页动画完成后,调用委托方法pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:方法

我希望我的最终页面状态略有不同,具体取决于用户是通过滑动还是点击来翻页。但是我想不出一种可靠的方法来确定导致翻页的原因。 pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted: 方法不提供该信息。

在我的 UIPageViewController 委托 (self) 中,调用了 gestureRecognizer:shouldReceiveTouch: 方法,但它被调用用于滑动(平移)和点击手势识别器,即使用户最终使用只有一个或另一个手势。在任一手势触摸屏幕时调用委托手势方法。所以这没有帮助。

我在页面视图中添加了一套触摸相关的拦截方法。对于 touchesBegan:withEvent: 我重置了一个标志。对于点击手势不调用的 touches:moved:,我设置了标志。这种方法可行,但它的级别太低,将来可能无法正确用于某些其他也会移动但不是 swipe/pan 的手势。而且 UIPageViewController 的点击手势似乎完全吞噬了触摸事件,所以甚至 touchesBegan:withEvent: 都没有被调用(这很奇怪)。

有什么方法可以稳健地区分UIPageViewController使用哪种翻页方式(点击或pan/swipe)来处理用户交互翻页?

gestureRecognizer:shouldReceiveTouch:中您可以检查手势类型。

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if gestureRecognizer is UITapGestureRecognizer {
       self.wasTap = true;
       self.wasSwipe = false;
    } else if gestureRecognizer is UISwipeGestureRecognizer {
       self.wasTap = false;
       self.wasSwipe = true;
    }
    return true;
}

然后在 pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted: 中根据为真的布尔值更改最终页面的状态。

真正的问题是如何确定几个手势识别器中的哪一个对发生的事情负责。

要理解的关键是任何手势识别器都可以安装多个 target/action。 UIPageViewController 在内部设置了自己的 target/actions,但这并不排除添加其他人。

在加载或实例化 UIPageViewController 后设置子 class 时,添加以下代码(或 Swift 等效代码):

for (UIGestureRecognizer *gr in self.gestureRecognizers) {
    if ([gr class] == [UIPanGestureRecognizer class])
        [gr addTarget:self action:@selector(panGestureOccurred)];
     else if ([gr class] == [UITapGestureRecognizer class])
        [gr addTarget:self action:@selector(tapGestureOccurred)];
    }

然后,将两个target/action方法添加到sub-class:

- (void)tapGestureOccurred
{
    // Set a flag here to rely on later after the page turn
}

- (void)panGestureOccurred
{
    // Reset a flag here to rely on later after the page turn
}

这显然适用于任何其他类型的手势,但目前 UIPageViewController 似乎只支持平移和点击手势。

当用户触摸屏幕并移动 finger/stylus 时,

panGestureOccurred 将被多次调用。 tapGestureOccurred 只被调用一次。

但是这两种方法只会调用其中一种,这取决于页面视图控制器以其无限智慧决定胜出的手势识别器。这一切似乎比原始问题中提出的太低级别 touchesBegantouchesMoved 想法更有效。