正确的 UIGestureRecognizer 和委托设计

Proper UIGestureRecognizer and Delegate design

这是一个非常假设的问题,只是为了理解正确的设计,但假设我有两个自定义 UIView。

其中一个本质上是一个我称之为抽屉的容器。它的目的是隐藏和显示内容。它很像 iOS 上的通知中心,您可以在其中滑动以将其拉开,然后向上轻弹以将其关闭。它是一个通用容器,不能包含任何其他 UIView。它有一个 UIPanGestureRecognizer 来跟踪拉动它的手指 open/closed。它也可能有一个 UISwipeGestureRecognizer 来检测 "flick".

另一个视图是具有 UIPan/Rotation/Pinch GestureRecognizers 的自定义地图小部件。

我认为抽屉视图应该是 Pan/Swipe GestureRecognizers 的 UIGestureRecognizerDelegate,这样它就可以防止触摸传递,除非用户正在抓取 "the handle"。

我的第一直觉是让地图成为 pan/rotation/pinch 手势的 UIGestureRecognizerDelegate,这样它就可以让它们同时 运行。

我遇到的问题是,在抽屉完全打开之前,我真的不希望地图接收任何触摸或开始识别手势。我希望能够在抽屉本身中自动强制执行此行为,以便它适用于开箱即用的所有子视图。

我能想到的唯一方法是将所有手势处理程序连接到 ViewController 并让它做所有事情,但对我来说这会破坏封装,因为现在它必须知道地图手势需要同时 运行,抽屉只能触摸它的手柄,地图只能在打开时触摸。

有哪些方法可以让逻辑保留在我认为它所属的视图中?

我会做这样的事情来在平移时禁用抽屉的子视图。基本上遍历抽屉的子视图并取消对它们的交互。

[self.subviews enumerateObjectsUsingBlock:^(UIView *subview, NSUInteger idx, BOOL *stop){
    subview.userInteractionEnabled = NO;
}];

当您想在子视图上重新启用用户交互时,再次使用类似的东西。

这应该已经 Just Work™。手势识别器附加到视图;当识别出连续手势时,与该手势关联的所有后续触摸都与该视图关联。

所以在你的例子中,当抽屉盘被识别时,与该盘相关的任何触摸都不应该导致你的地图视图的 pan/pinch/rotation 手势行为(除非你明确指定他们应该使用适当的委托方法).

或者你的意思是你想阻止用户在打开抽屉的中途使用另一个手指(即另一个手势)开始滚动(半可见)地图?如果是这样,您应该将抽屉的 contentView(或等效项)上的 userInteractionEnabled 设置为 UIGestureRecognizerStateBegan/Changed 上的 NO 并再次设置 YES UIGestureRecognizerStateEnded/Cancelled.