简体   繁体   English

如何过滤UIScrollView的触摸事件?

[英]How to filter touch events for a UIScrollView?

I have a view that displays a PDF. 我有一个显示PDF的视图。 It should be zoomable, so I also created a UIScrollView, and in its delegate I implemented viewForZoomingInScrollView to return the PDF view. 它应该是可缩放的,因此我还创建了一个UIScrollView,并在其委托中实现了viewForZoomingInScrollView以返回PDF视图。 So far so good. 到现在为止还挺好。 However, when the user reaches the edge of a zoomed PDF page, I'd like to flip to the next page. 但是,当用户到达缩放的PDF页面的边缘时,我想跳到下一页。 Sounds easy, yet I can't seem to figure out how to do it. 听起来很简单,但我似乎还不知道该怎么做。

I've tried some different approaches: 我尝试了一些不同的方法:

  1. Using scrollViewDidScroll to detect if scrolling has reached the edge. 使用scrollViewDidScroll检测滚动是否已到达边缘。 The problem here is that if zoomScale is 1, and therefore scrolling is not possible, then this function is never called. 这里的问题是,如果zoomScale为1,因此无法滚动,则永远不会调用此函数。 But the UIScrollView still swallows all touch events, so I also can't detect reaching the edge in touchesMoved. 但是UIScrollView仍然吞噬所有触摸事件,因此我也无法在touchesMoved中检测到到达边缘。 Setting canCancelContentTouches to NO when not zoomed is not an option, as that would also prevent zooming in. 如果不进行缩放,则不能将canCancelContentTouches设置为NO,因为这也会阻止放大。

  2. Subclassing UIScrollView, and forwarding some of the touch events to the next responder. 子类化UIScrollView,并将某些触摸事件转发给下一个响应者。 Unfortunately when UIScrollView detects a drag operation and cancels the touch, touchesMoved and touchesEnded are not called even for the UIScrollView subclass anymore. 不幸的是,当UIScrollView检测到拖动操作并取消了触摸时,即使对于UIScrollView子类也不再调用touchesMoved和touchesEnded。 Again, setting canCancelContentTouches to NO is not good, as that would also prevent some desired UIScrollView functionality. 同样,将canCancelContentTouches设置为NO也不是一件好事,因为这也会阻止某些所需的UIScrollView功能。

  3. Creating a transparent view on top of the scroll view (as a sibling of it), so that this view gets all touch events first, and then forwarding some of the touches to the scroll view. 在滚动视图的顶部创建一个透明视图(作为其同级视图),以便该视图首先获取所有触摸事件,然后将某些触摸转发到滚动视图。 Unfortunately the scroll view doesn't respond to these calls. 不幸的是,滚动视图无法响应这些调用。

  4. I can't use touchesShouldCancelInContentView, becasue that doesn't get the actual touches as an argument, and whether or not I want the scroll view to handle the touch event also depends on the properties of the touch event itself (eg. a touch movement in a direction in which we're already at the edge should not be cancelled by the scroll view, but a movement in the other direction could be). 我不能使用touchesShouldCancelInContentView,因为它没有将实际的触摸作为参数,并且我是否希望滚动视图处理触摸事件还取决于触摸事件本身的属性(例如,触摸运动)滚动视图不应取消在我们已经处于边缘的方向上的移动,而可以在另一个方向上进行移动)。

Looks like whatever UIScrollView is doing is not initiated from touchesBegan / touchesMoved, but instead it gets some notifications about the touches way before that. 看起来UIScrollView所做的任何事情都不是从touchesBegan / touchesMoved启动的,而是之前获得了有关touches方式的一些通知。 Possibly in some undocumented way that I can't intercept, nor reproduce. 可能以某种无法记录的方式,我无法拦截或复制。

So is there any way to get notified about all touch movements done over a UIScrollView, while still being able to use (when certain conditions apply) the UIScrollView for zooming and scrolling? 那么,有什么方法可以通知UIScrollView上完成的所有触摸动作,同时仍然可以使用UIScrollView(在某些条件下)进行缩放和滚动?

Ok, so here's what I did in the end: 好的,这就是我最后要做的事情:

  • Leaving all scrolling and zooming up to UIScrollView, and handling page turning in the UIScrollViewDelegate's scrollViewDidEndDragging:willDecelerate: is almost a solution, except that this function is never called if the whole content is on-screen, so dragging / scrolling is not possible. 将所有滚动和缩放操作留给UIScrollView,并在UIScrollViewDelegate的scrollViewDidEndDragging:willDecelerate:中处理页面翻转几乎是一个解决方案,只是如果整个内容都在屏幕上,则永远不会调用此函数,因此无法进行拖动/滚动。
  • Swipes in this case are handled in a ViewController's touchesBegan / touchesEnded functions, but for this to work, we need to make sure that the UIScrollView does not cancel these events. 在这种情况下,滑动是在ViewController的touchesBegan / touchesEnded函数中处理的,但是要使其正常工作,我们需要确保UIScrollView不会取消这些事件。 However, in other cases the UIScrollView should be able to cancel touches so that it can do zooming and scrolling. 但是,在其他情况下,UIScrollView应该能够取消触摸,以便可以进行缩放和滚动。
  • The UIScrollView should be able to cancel touches if: 在以下情况下,UIScrollView应该能够取消触摸:
    • Scrolling is possible (and needed) because the whole content doesn't fit on screen (zoomScale > 1 in my case), OR 可以滚动(并且需要滚动)是因为整个内容无法显示在屏幕上(在我的情况下,zoomScale> 1),或者
    • The user touched the screen with two fingers, so that zooming in and out works. 用户用两根手指触摸屏幕,以便进行放大和缩小。
  • When scrolling is not possible, and the user single-touched the screen, then touches should not be cancelled, and touch events should be forwarded to the view controller. 当不可能滚动时,并且用户单触摸屏幕时,则不应取消触摸,并且应将触摸事件转发给视图控制器。

  • So I created a UIScrollView subclass. 因此,我创建了一个UIScrollView子类。

  • This subclass has a property pointing to the ViewController. 该子类具有指向ViewController的属性。
  • Using the touchesXXX methods I keep track of the current touch count. 使用touchesXXX方法,我可以跟踪当前的触摸计数。
  • I forward all touch events to the ViewController. 我将所有触摸事件转发到ViewController。
  • And finally, I've overridden touchesShouldCancelInContentView:, and return NO when zoomScale <= 1 and touchCount == 1. 最后,我重写touchesShouldCancelInContentView:,并在zoomScale <= 1和touchCount == 1时返回NO。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM