Dragging an UIView inside UIScrollView

Solution 1:

I was struggling with this same problem - I was trying to do a interface with a lot of "cards" (UIView subclasses) on a cork board, and have the cork board area scrollable, but still able to drag-and-drop the cards. I was doing the hitTest() solution above, but one of the Apple engineers asked me why I was doing it that way. The simpler solution they suggested was as follows:

1) In the UIScrollView class, set the value of canCancelContentTouches to NO - this tells the UIScrollView class to allow touches within subviews (or, in this case, in subviews of subviews).

2) In my "card" class, set exclusiveTouch to YES - this tells the subview it owns the touches inside of it.

After this, I was able to drag around the cards and still scroll the subview. It's a lot simpler and cleaner than the hitTest() solution above.

(BTW, for extra credit, if you are using iOS 3.2 or 4.0 or later, use the UIPanGestureRecognizer class to handle the drag and drop logic - the drag and drop motion is a lot smoother than overriding touchesBegan()/touchesMoved()/touchesEnded().)

Solution 2:

Solved: it turned out that there should be also touchesBegan: and touchesEnded: implementations (in my case having empty methods helped) in the tile, otherwise the gesture started propagating to parent views, and they were intercepting the gesture somehow. Dependency on the drag speed was imaginary.

Solution 3:

At first, set:

scrollview.canCancelContentTouches = NO;

yourSubView. exclusiveTouch = YES;

Then in your subview gesture handle function,

- (void)handleSubviewMove:(UIPanGestureRecognizer *)gesture {

if(gesture.state == UIGestureRecognizerStateBegan) {
    if(_parentScrollView != nil) {
        _parentScrollView.scrollEnabled = NO;
    }
}
if(gesture.state == UIGestureRecognizerStateEnded) {
    if(_parentScrollView != nil) {
        _parentScrollView.scrollEnabled = YES;
    }
}

CGPoint translation = [gesture translationInView:[self superview]];
/* handle your view's movement here. */
[gesture setTranslation:CGPointZero inView:[self superview]];
}