向前移动到一个UIScrollView

我有两个视图控制器。 视图控制器A具有UIScrollView并呈现视图控制器B.该呈现是交互式的并由scrollView.contentOffset控制。

我想集成一个交互式的解雇过渡:当平移时,ViewController B应该被交互式地解雇。 交互式解散转换也应该控制ViewController的scrollView。

我第一次尝试使用UIPanGestureRecognizer并根据平移距离设置scrollView.contentOffset 。 这工作,但是当平移手势结束时,scrollView偏移量必须被animation到结束位置。 使用-[UIScrollView setContentOffset:animated:不是一个好的解决scheme,因为它使用线性animation,不考虑当前的摇摄速度,并且不会很好地减速。

所以我认为应该有可能从我的平移手势识别器提供触摸事件到滚动视图。 这应该会给我们所有漂亮的滚动视图animation行为。

我尝试在我的UIPanGestureRecognizer子类中重写-touchesBegan/Moved/Ended/Cancelled withEvent:方法,如下所示:

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [scrollView touchesBegan:touches withEvent:event]; [scrollView.panGestureRecognizer touchesBegan:touches withEvent:event]; [super touchesBegan:touches withEvent:event]; } 

但显然有些东西阻止了滚动视图进入tracking模式。 (它确实去dragging = YES但这是关于它。)我validation了scrollView是userInteractionEnabled ,不隐藏并添加到视图层次结构。

那么如何将我的触摸事件转发给UIScrollView呢?

在阅读了一个描述UIScrollView事件stream程的有趣答案之后,我得出结论:试图从手势识别器“远程控制”滚动视图可能是非常难以实现的,因为触摸在被路由到视图和手势识别器时被突变。 由于UITouch不符合NSCopying我们也无法克隆触摸事件,以便在未修改的状态下以后发送。

虽然没有真正解决我所要求的问题,但我find了解决方法来完成我所需要的工作。 我只是添加了一个滚动视图来查看控制器B,并与VC A的滚动视图(在垂直滚动时添加到视图层次结构中)同步:

 // delegate of VC B's scrollView - (void)scrollViewDidScroll:(UIScrollView*)scrollView scrollViewA.contentOffset = scrollView.contentOffset; } 

感谢Friedrich Markgraf 提出了这个想法 。

尝试UIScrollView并重写hitTest:withEvent:这样UIScrollView可以在界限之外进行触摸了。 然后你可以免费得到所有漂亮的UIScrollViewanimation。 像这样的东西:

 @interface MagicScrollView : UIScrollView @end @implementation MagicScrollView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // Intercept touches 100pt outside this view's bounds on all sides. Customize this for the touch area you want to intercept if (CGRectContainsPoint(CGRectInset(self.bounds, -100, -100), point)) { return self; } return nil; } @end 

或者在Swift(感谢Edwin Vermeer!)

 class MagicScrollView: UIScrollView { override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { if CGRectContainsPoint(CGRectInset(self.bounds, -100, -100), point) { return self } return nil } } 

您可能还需要在UIScrollView的超级视图中覆盖pointInside:withEvent:取决于您的布局。

有关更多信息,请参阅以下问题: uiview的界限之外的交互

也许你可以尝试使用UIPanGesture委托中的方法:

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

我不知道它会如何反应,因为你的观点是模态的。 但也许它可以成功,而不会直接触及beginTouch等,这是一个痛苦的屁股。

告诉我,如果有帮助?

作为@johnboiles解决scheme的补充。 当你捕捉整个矩形,那么触动scrollview中的元素将被跳过。 你可以添加附加的触摸区域,并为正常的滚动视图只是传递给super.hitTest像这样:

 class MagicScrollView: UIScrollView { override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { if CGRectContainsPoint(CGRect(x: self.bounds.origin.x - 30, y: self.bounds.origin.y, width: 30, height: self.bounds.size.height), point) { return self } if CGRectContainsPoint(CGRect(x: self.bounds.origin.x + self.bounds.size.width, y: self.bounds.origin.y, width: 30, height: self.bounds.size.height), point) { return self } return super.hitTest(point, withEvent: event) } } 

我有一个超视图内的滚动视图有左和右的边界。 为了使这些边界可以滚动,这是我的方法:

 class CustomScrollView: UIScrollView { override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { if let view = super.hitTest(point, withEvent: event) { return view } guard let superview = superview else { return nil } return superview.hitTest(superview.convertPoint(point, fromView: self), withEvent: event) } override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool { if super.pointInside(point, withEvent: event) { return true } guard let superview = superview else { return false } return superview.pointInside(superview.convertPoint(point, fromView: self), withEvent: event) } } 

完美的作品