Search code examples
iosdrag-and-dropuipopovercontroller

UIPopoverController Drag and Drop


I have a question which is mostly answered by this question.

However, I have a slight variation of the task. I want to drag and drop UIImageViews from a UIPopover controller to another UIView, but the number of image views contained in the popover exceeds the iPad's height, meaning users must also be able to scroll the popover's content (which is presented in a UITableView).

I'm using a UIPanGestureRecognizer to detect the attempt to drag and drop, but this essentially disables the scrolling by intercepting the event. I think I know how to handle this. Scrolling is essentially a vertical move, while dragging and dropping is more of a lateral move. So, I'm thinking that when I detect the beginning of a drag and drop, I have to detect if it's primarily a vertical move. If so, I have to somehow trigger scrolling and pass the motion off to that "handler" instead.

Any a) feedback on whether this is the right approach, and b) any pointers on the implementation?


Solution

  • I successfully completed this and would like to share the solution.

    Because we're dealing with a UITableView inside a UIPopoverController, the first issue you have to deal with is the fact that the user may simply want to scroll the tableview, not drag the contents of one of its cells (in this case a UIImageView). I solved this by attaching a custom gesture recognizer to my custom image view class, meaning that every image view loaded into the table view had a custom gesture recognizer attached to it.

    The crux of that gesture recognizer was the following code inside the touchesMoved method:

    if (ABS(currentTouchLocation.y-self.firstTouchLocation.y) > 4 && ABS(currentTouchLocation.x-self.firstTouchLocation.x)< 2)
    {
    
        self.state = UIGestureRecognizerStateFailed;
    
    }
    

    Causing the gesture recognizer to fail allows the touch event to proceed to the table view, as normal. The use of > 4 and < 2 conditions controls the angle at which one considers an action to be a vertical scroll versus a drag and drop.

    The rest of the code goes in the gesture's action method. Here, one of the first things you do is create a copy of the tableview cell's image view and add it to the main window:

    self.newImageView =  [[ElementImageView alloc] initWithImage:self.image];
        self.newImageView.frame = [self.superview convertRect:self.frame toView:[UIApplication sharedApplication].keyWindow];
    
        [[UIApplication sharedApplication].keyWindow addSubview:self.newImageView];
    

    It was at this point I struggled the most. I kept trying to find a way to transfer the touch to this new image view, or to somehow trigger a touch programmatically, so my dragging motion could carry on seamlessly. This was totally unnecessary. Dragging is implemented by applying to your view the x/y delta between the first position of its associated touch versus the latest position. Instead, I simply left my original image view where it was and applied the delta to my copy.

    If you follow this approach, you can easily drag a copy of a UIImageView from a UITableView/UIPopOverController anywhere on the screen.