Adding long tap functionality to UIButton

A lot of times we find ourselves needing a bit more flexibility in the actions our UIButton respond to. The standard tap is great but some time you want to handle double tapping – which is also pretty straight forward and covered in lots of other

blogs.

We wanted something a bit more complicated – we wanted to be able to handle the basic button functions but at the same time to be able to handle long taps for a different action (like shaking items for editing/deleting).

So to get the best of all worlds we decided to subclass UIButton and create some custom handling of touches. We’re going to go over 3 basic steps:

Step 1 Subclass UIButton and implement touches methods

Step 2 Implement detection for long tap by counting time from touchesBegan to touchesEnded and consume the event accordingly

Step 3 Create a buttonDidLongTap protocol method for more flexible handling of long tap event

So nothing to fancy here. Let’s dive into it:

Create a new file – name it UIButtonWithLongTap. Into the UIButtonWithLongTap.h file write:


@protocol UIButtonWithLongTapDelegate

@optional

-(void)buttonDidLongTap:(NSNumber*)tag;

@end

@interface UIButtonWithLongTap : UIButton {

id delegate;

BOOL consumedTap;

}

@property (nonatomic, assign) id delegate;

@end

Basically here we are setting up delegate and delegate method we will call when we detect a long tap on our button. So we can be very flexible with what we do with this utility.
Now let’s go to our UIButtonWithLongTap.m file and start filling it with all our codely goodness.
We’ll implement the call to our delegate method like you normally would – just passing along the method call to our delegate (assuming it responds to it)

-(void)detecetedLongTap{

consumedTap = YES;

if (delegate != nil && [delegate respondsToSelector:@selector(buttonDidLongTap:)]) {

  [delegate performSelector:@selector(buttonDidLongTap:) withObject:[NSNumber numberWithInt:self.tag]];

}

}

Now comes the tricky bit – we need to start counting time from the moment a touch begins until it ends – check if it’s long enough for us to count as a long tap and call the method we just defined. We’ll do this but overriding the touchesBegan method and calling the performSelector using the afterDelay flag. You can set the amount of time you’d want for long tap here.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

 consumedTap = NO;

 [super touchesBegan:touches withEvent:event];

 [self performSelector:@selector(detecetedLongTap) withObject:nil afterDelay:1.0];
}

Ok so now every time the button is pressed we tell our button to perform our detectedLongTap method after 1.0. But how do we cancel this if the tap was to short? This is where we implement our touchesEnded method with a nice little method belonging to NSObject called cancelPreviousPerformRequestsWithTarget. This will cancel our performSelector request if the action has not been consumed yet.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent*)event{

if (!consumedTap) {

[super touchesEnded:touches withEvent:event];

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(detecetedLongTap) object:nil];

}

}

That’s it – we’re done! Now all you have to do is replace your UIButton with UIButtonWithLongTap and set your delegate to handle the response you want.
Edit: You may need to do some image swapping/highlighting on the button manually for a nice finish. We did this in our code. If you run into trouble post us a comment and we’ll put up the whole code for this component.

Facebook comments:

One Response to “Adding long tap functionality to UIButton”

  1. K says:

    Really useful & kind of sexy solution;-) Thanks a lot

Leave a Reply