问题 转发到UIScrollView
            
                我有两个视图控制器。视图控制器A有一个 UIScrollView 并呈现视图控制器B.该演示是交互式的并由控制 scrollView.contentOffset。
我想整合一个交互式消除过渡:当平移时,ViewController B应该以交互方式被解雇。交互式dismiss转换还应控制ViewController的scrollView。
我的第一次尝试是使用了 UIPanGestureRecognizer 并设置 scrollView.contentOffset 根据平移距离。这是有效的,但是当平移手势结束时,必须将scrollView偏移动画到结束位置。运用 -[UIScrollView setContentOffset:animated: 不是一个好的解决方案,因为它使用线性动画,不考虑当前的平移速度,并且不会很好地减速。
所以我认为应该可以将我的平移手势识别器中的触摸事件提供给滚动视图。这应该给我们所有漂亮的滚动视图动画行为。
我试过压倒了 -touchesBegan/Moved/Ended/Cancelled withEvent: 在我的方法 UIPanGestureRecognizer 像这样的子类:
- (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 但这就是它。)我验证了scrollView是 userInteractionEnabled,不隐藏并添加到视图层次结构中。
那么我怎样才能将我的触摸事件转发给 UIScrollView?
             
            
            
                 4236            
            
                 2018-02-04 13:49            
            起源
            
            
            
            
            
            答案:
            
            
            
看完之后 有趣的答案 说明 UIScrollView在事件流程中,我得出的结论是,尝试从手势识别器“远程控制”滚动视图可能很难实现,因为触摸在被路由到视图和手势识别器时会发生变化。以来 UITouch 不符合 NSCopying 我们也无法克隆触摸事件,以便稍后在未修改状态下发送它们。
虽然没有真正解决我要求的问题,但我找到了解决方法来完成我需要的工作。我刚刚添加了一个滚动视图来查看控制器B并将其与VC A的滚动视图同步(在垂直滚动时添加到视图层次结构中):
// delegate of VC B's scrollView
- (void)scrollViewDidScroll:(UIScrollView*)scrollView
    scrollViewA.contentOffset = scrollView.contentOffset;
}
感谢Friedrich Markgraf 提出了这个想法。
 
                
                     11
                
                
                     2018-02-05 22:19
                
尝试继承 UIScrollView 并压倒一切 hitTest:withEvent: 所以这样 UIScrollView 接受超出界限的接触。那你得到了所有的好 UIScrollView 动画免费。像这样的东西:
@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
    } 
}
您可能还需要覆盖 pointInside:withEvent: 在...上 UIScrollView超级视图,取决于你的布局。
有关详细信息,请参阅以下问题: 超越uiview界限的互动
 
                
                     3
                
                
                     2017-12-08 06:12
                
也许你可以尝试在UIPanGesture委托中使用该方法:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
我不知道它会如何反应,因为你的观点是模态的。但也许它可以成功,如果没有直接使用beginTouch等触摸,这是一个痛苦的屁股。
告诉我它是否有帮助?
 
                
                     0
                
                
                     2018-02-04 17:05
                
作为@johnboiles解决方案的补充。当您捕获整个rect时,将跳过对scrollview内部元素的触摸。您可以添加aditional触摸区域,对于普通的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)
    }
}
 
                
                     0
                
                
                     2018-06-23 13:42
                
我在superview里面有一个滚动视图,有左右边框。为了使这些边框可滚动,这是我的方法:
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)
  }
}
完美的工作
 
                
                     0
                
                
                     2017-10-11 09:53