Search code examples
objective-cioscocoa-touchuiviewuitouch

Prevent dragging UIButton outside of its UIView


I've got two UIViews on my window: one to hold player scores, (a sidebar), and a main play area. They both fit on the UIWindow, and neither scroll. The user can drag UIButtons around on the main play area – but at present, they can drop them onto the sidebar. Once they do, they can't drag them again to bring them back, presumably because you're then tapping on the second view, which doesn't contain the button in question.

I'd like to prevent anything inside the main view being moved onto the sidebar view. I've managed this, but I need the drag to be released if the player's finger moves off that view. With the code below, the button keeps moving with the finger, but just won't go past the X coordinate of the view. How can I go about this? Dragging is enabled using this call:

[firstButton addTarget: self action: @selector(wasDragged: withEvent:) forControlEvents: UIControlEventTouchDragInside];

To this method:

- (void) wasDragged: (UIButton *) button withEvent: (UIEvent *) event
{
    if (button == firstButton) {
        UITouch *touch = [[event touchesForView:button] anyObject];
        CGPoint previousLocation = [touch previousLocationInView:button];
        CGPoint location = [touch locationInView:button];
        CGFloat delta_x = location.x - previousLocation.x;
        CGFloat delta_y = location.y - previousLocation.y;
        if ((button.center.x + delta_x) < 352)
        {
            button.center = CGPointMake(button.center.x + delta_x, button.center.y + delta_y);
        } else {
            button.center = CGPointMake(345, button.center.y + delta_y);
        }
    }
}

Solution

  • implement

    -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

    touch delegate method, then check the location of the UITouch, if the location is outside of the bounds you want to allow (the first view), then don't move it any further. You could also kill the touch at the point the user drags outside the view using a BOOL iVar

    //In .h file
    BOOL touchedOutside;
    
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        touchedOutside = NO;
    }
    
    -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
        if (!touchedOutside) {  
            UITouch *touch = [[event allTouches] anyObject];
            CGPoint location = [touch locationInView:firstView];
    
              if (location.x < UPPER_XLIMIT && location.x > LOWER_XLIMIT) {
                  if (location.y < UPPER_YLIMIT && location.x > LOWER_YLIMIT) {
    
                      //Moved within acceptable bounds
                      button.centre = location;
                  }
              } else {
                  //This will end the touch sequence
                  touchedOutside = YES;
    
                  //This is optional really, but you can implement 
                  //touchesCancelled: to handle the end of the touch 
                  //sequence, and execute the code immediately rather than
                  //waiting for the user to remove the finger from the screen
                  [self touchesCancelled:touches withEvent:event];   
        }
    }