Forward touches to a UIScrollView

后端 未结 4 1282
一个人的身影
一个人的身影 2021-01-04 08:32

I have two view controllers. View controller A has a UIScrollView and presents view controller B. The presentation is interactive and controlled by the sc

相关标签:
4条回答
  • 2021-01-04 09:03

    As an addition to solution of @johnboiles. When you catch the entire rect, then touches on elements inside the scrollview will be skipped. You could add aditional touch areas and for the normal scrollview just pass it on to the super.hitTest like this:

    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 讨论(0)
  • 2021-01-04 09:11

    After reading an interesting answer describing UIScrollView's event flow, I came to the conclusion that trying to "remote control" a scroll view from a gesture recognizer is probably very hard to achieve because touches are mutated while being routed to views and gesture recognizers. Since UITouch doesn't conform to NSCopying we also can't clone touch events in order to send them later in unmodified state.

    While not really solving the problem I asked for, I found a workaround to accomplish what I need. I just added a scroll view to view controller B and synced it with VC A's scroll view (which is added to the view hierarchy when vertically scrolling):

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

    Thanks to Friedrich Markgraf who came up with the idea.

    0 讨论(0)
  • 2021-01-04 09:17

    I have a scrollview inside of a superview to have left and right borders. To make those borders scrollable, this were my approach :

    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)
      }
    }
    

    Works perfectly

    0 讨论(0)
  • 2021-01-04 09:19

    Try subclassing the UIScrollView and overriding hitTest:withEvent: so that the UIScrollView picks up touches outside its bounds. Then you get all the nice UIScrollView animations for free. Something like this:

    @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
    

    Or in Swift (Thanks 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
        } 
    }
    

    You may also need to override pointInside:withEvent: on the UIScrollView's superview, depending on your layout.

    See the following question for more info: interaction beyond bounds of uiview

    0 讨论(0)
提交回复
热议问题