I am new to iOS/objective-C and I wanted to know how to build custom gestures. In particular, if a user taps the top right of the screen and slides his/her finger down the edge
Creating a UIGestureRecognizer
subclass is a bit involved to do in a solid way. I very much recommend watching the WWDC2010 videos on the subject Session 120 - Simplifying Touch Event Handling with Gesture Recognizers
& Session 121 - Advanced Gesture Recognition
. They are thorough and well done.
But for a very simple example, based on your question, I created a very simple gesture recognizer that fires when a user touches the upper left quadrant of the attached view and slides their finger down to the lower right quadrant of the attached view and picks up their finger, without sliding to the left side of the attached view.
RightSlidedown.h:
#import // This import is essential
@interface RightSlidedown : UIGestureRecognizer
@end
RightSlidedown.m
#import "RightSlidedown.h"
@implementation RightSlidedown
-(id)initWithTarget:(id)target action:(SEL)action{
if ((self = [super initWithTarget:target action:action])){
// so simple there's no setup
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if ([touch locationInView:self.view].x < CGRectGetMidX(self.view.bounds)) self.state = UIGestureRecognizerStateFailed;
else if ([touch locationInView:self.view].y > CGRectGetMidY(self.view.bounds)) self.state = UIGestureRecognizerStateFailed;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if([touch locationInView:self.view].x < CGRectGetMidX(self.view.bounds)) self.state = UIGestureRecognizerStateFailed;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if ([touch locationInView:self.view].x < CGRectGetMidX(self.view.bounds)) self.state = UIGestureRecognizerStateFailed;
else if ([touch locationInView:self.view].y < CGRectGetMidY(self.view.bounds)) self.state = UIGestureRecognizerStateFailed;
else {
// setting the state to recognized fires the target/action pair of the recognizer
self.state = UIGestureRecognizerStateRecognized;
}
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
self.state = UIGestureRecognizerStateCancelled;
}
-(void)reset{
// so simple there's no reset
}
@end
So basically the gesture recognizer gets what seems like the standard touch events. (They're not, but they act that way). As you respond to the movements you change the state
property of your gesture recognizer.
There are two basic types of recognizers, "Discrete" (think tap gesture) and "Continuous" (think pan gesture). Both types automatically start in UIGestureRecognizerStatePossible
in the beginning.
For a "Discrete" type, like this one, your goal is to get to state UIGestureRecognizerStateRecognized
or UIGestureRecognizerStateFailed
as soon as possible.
The ideal usage of this example would be to add the RightSlidedown
gesture recognizer to the main view of a new "Single View Application" in the view controller's viewDidLoad
.
[self.view addGestureRecognizer:[[RightSlidedown alloc] initWithTarget:self action:@selector(rightSlide:)]];
Then a simple action method is all that's required, like so:
-(void)rightSlide:(RightSlidedown *)rsd{
NSLog(@"right slide");
}