aritchie
aritchie

Reputation: 601

touchesEnded not called when detecting a long press

In my app I have a UIView with two UITableViews side by side. Layered on top of these is a UIView (all done in Storyboards).

enter image description here

It is set up to drag and drop cells between the tables by attaching to the top UIView, DnD Overlay View (using some open source code, https://github.com/josh2112/iPad-UITableView-DnD-Demo). All of this works fine until the tables have enough cells to warrant scrolling - I can't get them to scroll, because every time I touch a cell it pops it out to be dragged.

So, I want to try to make the pop out function from a long press instead of instantly. Here's what I have:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog( @"touchesBegan" );
    UITouch* touch = [touches anyObject];
    longPress = NO;

    [self performSelector:@selector(longPress:) withObject:touch afterDelay:2.0];
}

- (void)longPress:(UITouch *)touch{
BOOL inDragSource = NO;
longPress = YES;
// Was the touch over a drag source?
for( UIView<DragSource>* dragSource in dragSources ) {
    CGPoint point = [touch locationInView:dragSource];
    if( CGRectContainsPoint( dragSource.bounds, point )) {
        NSLog( @"Detected touch inside drag source!!!" );
        inDragSource = YES;

        // Ask the drag source for a draggable
        UIView* draggable = [dragSource popItemForDragFrom:point];
        if( draggable != nil ) {
            NSLog( @"Start drag on thing: %@", draggable );
            dragOperation = [[DragOperation alloc] initWithDraggable:draggable dragSource:dragSource initialPoint:draggable.center];

            // Unattach the draggable from its parent view and attach it to the overlay view, using the touch
            // location as the center point.
            [self addSubview:draggable];
            draggable.center = [self convertPoint:draggable.center fromView:dragSource];
            draggable.layer.masksToBounds = NO;
            draggable.layer.cornerRadius = 8;
            draggable.layer.shadowOffset = CGSizeMake( 7, 7 );
            draggable.layer.shadowRadius = 5;
            draggable.layer.shadowOpacity = 0.5;

            [UIView animateWithDuration:0.1f animations:^{
                draggable.center = [touch locationInView:self];
                draggable.transform = CGAffineTransformMakeScale( 1.2f, 1.2f );
            }];

            // If the drag source is also a drop target, tell it the draggable is hovering over it.
            if( [dragSource conformsToProtocol:@protocol(DropTarget)] ) {
                [self notifyDraggableEntered:(UIView<DropTarget>*)dragSource atPoint:point];
            }

            return;
        }
    }
}

}  


- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if( dragOperation == nil ) return;

UITouch* touch = [touches anyObject];

if(!longPress){
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(longPress:) object:touch];
}
else{
    [self setHighlight:NO onDropTarget:dragOperation.currentDropTarget];

    // If we have a current drop target, drop the draggable there
    if( dragOperation.currentDropTarget != nil ) {
        NSLog( @"Transferring draggable to drop target!" );
        CGPoint point = [touch locationInView:dragOperation.currentDropTarget];

        CGPoint adjustedPoint = [dragOperation.currentDropTarget actualDropPointForLocation:point];
        [self animateDropOn:dragOperation.currentDropTarget atPoint:adjustedPoint withDuration:0.1f];
    }
    else {
        // If the original drag source is also a drop target, put the draggable back in its
        // original spot.
        if( [dragOperation.dragSource conformsToProtocol:@protocol(DropTarget)] ) {
            NSLog( @"Transferring draggable back to source" );
            [self animateDropOn:(UIView<DropTarget>*)dragOperation.dragSource atPoint:dragOperation.initialPoint withDuration:0.3f];
        }
        else {
            // Otherwise, just kill it?
            NSLog( @"Killing draggable, nobody wants it :-(" );
            [dragOperation.draggable removeFromSuperview];
            dragOperation = 0;
        }
    }
}
}

So now, if I touch anywhere, touchesBegan is fired, then longPress, even if it isn't a long press. touchesEnded doesn't get hit to cancel the previous perform request. touchesCancelled doesn't get hit either.

Is there anything obvious I'm doing wrong here?

Upvotes: 1

Views: 1429

Answers (1)

iPatel
iPatel

Reputation: 47059

You need to add UILongPressGestureRecognizer on your controller

Here i provide UILongPressGestureRecognizer on UIButton just for example

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(btnCaptureTapped:)];
longPress.minimumPressDuration = 1.30f; // here you can set it as per your requirement.
[self.MyButtonName addGestureRecognizer:longPress]; 

And method call of UILongPressGestureRecognizer

- (void)btnCaptureTapped:(UILongPressGestureRecognizer*)gesture
{
   // do your  stuff
}

And also add click even on UIButton is also work for you.

such like

[self.MyButtonName addTarget:self action:@selector(MyButtonNameTapped:) forControlEvents:UIControlEventTouchUpInside];

Upvotes: 1

Related Questions