Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I drag a UICollectionViewCell from one UICollectionView to another UICollectionView?

I am making an iPad application. On one page of this application, there is a UICollectionView on the left-hand side and another UICollectionView on the right hand side. Each UICollectionView is one column wide.

The functionality I desire is as follows: Each UICollectionViewCell on the left hand side should be able to be dragged to the UICollectionView on the right hand side. If this is not possible, then at least a UICollectionViewCell should be able to be dragged out of the left UICollectionView and then I'll handle having it appear in the righthand UICollectionView.

Is this functionality possible? If so, how would I go about implementing it?

like image 482
erikt Avatar asked Jun 21 '13 14:06

erikt


2 Answers

You would want to attach a long press gesture recognizer to the common superview of both collectionViews. The drag operation is triggered by the long-press, and the entire transaction is handled within that recognizer. Because the pan gesture is used for scrolling the collectionviews, you will run into problems in trying to use the pan recognizer.

The key thing is the gesture recognizer needs to be attached the COMMON superview, and all points and rectangles are converted to the coordinate system of the superview.

This isn't the exact code (this moves from a CV to another view) but the process would be similar (NOTE: I have tried to strip out some code that would be irrelevant to your app, so I could have messed something up in the process -- but the concept holds):

- (void) processLongPress:(UILongPressGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateChanged)
{
    if (!dragView)
        return;
    CGPoint location = [sender locationInView:self.view];
    CGPoint translation;
    translation.x = location.x - dragViewStartLocation.x;
    translation.y = location.y - dragViewStartLocation.y;
    CGAffineTransform theTransform = dragView.transform;
    theTransform.tx = translation.x;
    theTransform.ty = translation.y;
    dragView.transform = theTransform;
    [self.view bringSubviewToFront:dragView];
    return;
}   

if (sender.state == UIGestureRecognizerStateBegan)
{
    //  if point gives a valid collectionView indexPath we are doing a long press on a picture item to begin a drag
    //  & drop operation.
    CGPoint point = [sender locationInView:collectionView];
    dragViewIndexPath = [collectionView indexPathForItemAtPoint:point];
    if (dragViewIndexPath)  // i.e., selected item in collection view.
    {
        UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:dragViewIndexPath];
        dragView = [cell.contentView viewWithTag:cell.tag];
        [dragView removeFromSuperview];
        [self.view addSubview:dragView];
        dragView.center = [collectionView convertPoint:point toView:self.view];
        dragViewStartLocation = dragView.center;
        [self.view bringSubviewToFront:dragView];
    }
    return;
}

if (sender.state == UIGestureRecognizerStateEnded)
{
    if (dragView)
    {
        dragView.center = CGPointMake(dragView.center.x + dragView.transform.tx, dragView.center.y + dragView.transform.ty);
        CGAffineTransform theTransform = dragView.transform;
        theTransform.tx = 0.0f;
        theTransform.ty = 0.0f;
        UIView *dropTarget = [self mapDisplayModeToReceiverView];   // get drop target

        CGRect convertedTargetFrame = [self.view convertRect:dropTarget.frame fromView:dropTarget.superview];
        if (CGRectContainsPoint(convertedTargetFrame, dragView.center)) // if so, then drop it.
        {
            ImageWithAttachedLabel *i = (ImageWithAttachedLabel *) dragView;
            [speakStrings addObject:[i.labelText stringByAppendingString:@". "]];
            UserData *uData = (UserData *)i.userDataObject;
            UIImage *image = [[UIImage alloc] initWithData:uData.image];
            CGRect newFrame = CGRectMake(0.0f, 0.0f, 140.0f, 140.0f);
            ImageWithAttachedLabel *newImage = [[ImageWithAttachedLabel alloc] initWithFrame:newFrame withImage:image withLabel:uData.itemName];
            newImage.tag = RECEIVERVIEW_MAGIC_NUMBER;
            [self.view addSubview:newImage];
            newImage.center = [receiverView convertPoint:dropTarget.center toView:self.view];
            [UIView animateWithDuration:0.35f animations:^{ newImage.transform = CGAffineTransformMakeScale(1.15f, 1.15f); newImage.transform = CGAffineTransformIdentity; }
                             completion:^(BOOL finished) {  if (finished)
                                                            {
                                                                [newImage removeFromSuperview];
                                                                newImage.frame = newFrame;
                                                                [dropTarget addSubview:newImage];
                                                                [dragView removeFromSuperview];
                                                                dragView=nil; }
                                                            }];

        }
        else
        {
            [dragView removeFromSuperview];
            dragView = nil;
        }

        [self reloadData];
        return;
    }
}
like image 149
RegularExpression Avatar answered Oct 11 '22 17:10

RegularExpression


There's no way to actually 'pass' a cell from a collection to the other, but you can do the following:

1) Once you detect that the user dragged a cell in the other collection, delete the cell from the first collection (let's call it Collection 1). You can maybe use a nice fade animation to make the cell disappear.

2) Add a cell to the second table with a nice animation (see the UICollectionView and UICollectionViewLayout methods and delegate methods for this).

like image 24
Gianluca Tranchedone Avatar answered Oct 11 '22 15:10

Gianluca Tranchedone