Last active
May 4, 2022 16:37
-
-
Save lamprosg/5141469 to your computer and use it in GitHub Desktop.
(iOS) Touches, taps and Gestures
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Touch events must be implemented in the class for ex. of the control that should handle it. If it doesn't it has to be | |
//implemented in the parent class (ex. if not in the uicontrol, uibutton,table cell, tableview etc then it will go to UIView. | |
//If UIView won't handle it, then it will go to the ViewController class. It can end up to the appdelegate class). | |
//You have to call the parent's function that will implement the event manually | |
//Four methods are used to notify a responder about touches. | |
//When the user first touches the screen, the system looks for a responder that has a method called touchesBegan:withEvent: | |
//Example | |
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event | |
{ | |
//How many taps were there | |
//UITouch *touch = [touches anyObject]; | |
NSUInteger numTaps = [[touches anyObject] tapCount]; | |
//Number of touches (fingers) currently pressed | |
NSUInteger numTouches = [touches count]; | |
// Do something here. | |
} //If numTaps=2 and numTouches=2 the user doubled tapped with both fingers | |
//Some times some controls don't care about touches in other controls. | |
//You can get a subset of touches that has only those touches that fall within a particular view from the event, like so | |
NSSet *myTouches = [event touchesForView:self.view]; | |
//Every UITouch represents a different finger | |
//Each finger is located at a different position on the screen | |
//You can find out the position of a specific finger using the UITouch object | |
CGPoint point = [touch locationInView:self]; | |
//You can get notified while the user is moving fingers across the screen by implementing | |
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event | |
//This method is called multiple times during a long drag | |
//Each time it is called, you will get another set of touches and another event | |
//you can also discover the previous location of a touch, which is the finger’s position the last time | |
//either touchesMoved:withEvent: or touchesBegan:withEvent: was called. | |
//When the user’s fingers are removed from the screen | |
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event | |
//is invoked | |
//If the user is in the middle of a gesture when something happens to interrupt it, like the phone ringing, this | |
-(void)touchesCancelled(NSSet *)touches withEvent:(UIEvent *)event | |
//is called | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*****************************************************/ | |
//Vertical and Horizaontal Swipe | |
/*****************************************************/ | |
@property (nonatomic) CGPoint gestureStartPoint; | |
---------------------------------- | |
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event | |
{ | |
//Grab any touch (we don't care about multiple touches here) | |
UITouch *touch = [touches anyObject]; | |
//Getting the position of the touch | |
self.gestureStartPoint = [touch locationInView:self.view]; | |
} | |
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event | |
{ | |
//Get the current position of the user's finger | |
UITouch *touch = [touches anyObject]; | |
CGPoint currentPosition = [touch locationInView:self.view]; | |
//Calculate how far the user’s finger has moved both horizontally and vertically from its starting position | |
//fabsf returns absolute value of float | |
CGFloat deltaX = fabsf(self.gestureStartPoint.x - currentPosition.x); | |
CGFloat deltaY = fabsf(self.gestureStartPoint.y - currentPosition.y); | |
//check to see if the user has moved far enough in one direction | |
//without having moved too far in the other to constitute a swipe. | |
if (deltaX >= kMinimumGestureLength && deltaY <= kMaximumVariance) | |
{ | |
//Horizontal swipe detected | |
[self performSelector:@selector(eraseText) withObject:nil afterDelay:2]; | |
} | |
else if (deltaY >= kMinimumGestureLength && deltaX <= kMaximumVariance) | |
{ | |
//Vertical swipe detected | |
[self performSelector:@selector(eraseText) withObject:nil afterDelay:2]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)reportHorizontalSwipe:(UIGestureRecognizer *)recognizer | |
{ | |
//Horizontal swipe detected | |
[self performSelector:@selector(eraseText) withObject:nil afterDelay:2]; | |
} | |
- (void)reportVerticalSwipe:(UIGestureRecognizer *)recognizer | |
{ | |
//Vertical swipe detected | |
[self performSelector:@selector(eraseText) withObject:nil afterDelay:2]; | |
} | |
- (void)viewDidLoad | |
{ | |
[super viewDidLoad]; | |
// Do any additional setup after loading the view, typically from a nib. | |
UISwipeGestureRecognizer *vertical = [[UISwipeGestureRecognizer alloc] | |
initWithTarget:self action:@selector(reportVerticalSwipe:)]; | |
vertical.direction = UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown; | |
//Instead of self.view we could put any control. Label. button, imageview etc.. | |
[self.view addGestureRecognizer:vertical]; | |
UISwipeGestureRecognizer *horizontal = [[UISwipeGestureRecognizer alloc] | |
initWithTarget:self action:@selector(reportHorizontalSwipe:)]; | |
horizontal.direction = UISwipeGestureRecognizerDirectionLeft| UISwipeGestureRecognizerDirectionRight; | |
[self.view addGestureRecognizer:horizontal]; | |
} | |
/***************************************************/ | |
//Let's say you want to put a swipe in a cell at the cellforrow function | |
// add swipe gesture to the cell so more options will appear | |
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(cellSwiped:)]; | |
swipe.direction = UISwipeGestureRecognizerDirectionLeft| UISwipeGestureRecognizerDirectionRight; | |
[cell addGestureRecognizer:swipe]; | |
#pragma mark - Cell is swiped | |
-(void) cellSwiped:(UIGestureRecognizer *)recognizer { | |
CGPoint location = [recognizer locationInView:self.tableView]; | |
NSIndexPath *swipedIndexPath = [self.tableView indexPathForRowAtPoint:location]; | |
TweetCell *swipedcell = (TweetCell*) [self.tableView cellForRowAtIndexPath:swipedIndexPath]; | |
[swipedcell toggleSwipedView]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)reportHorizontalSwipe:(UIGestureRecognizer *)recognizer | |
{ | |
self.label.text = [NSString stringWithFormat:@"%@Horizontal swipe detected", | |
[self descriptionForTouchCount:[recognizer numberOfTouches]]]; | |
[self performSelector:@selector(eraseText) withObject:nil afterDelay:2]; | |
} | |
- (void)reportVerticalSwipe:(UIGestureRecognizer *)recognizer | |
{ | |
self.label.text = [NSString stringWithFormat:@"%@Vertical swipe detected", | |
[self descriptionForTouchCount:[recognizer numberOfTouches]]]; | |
[self performSelector:@selector(eraseText) withObject:nil afterDelay:2]; | |
} | |
- (NSString *)descriptionForTouchCount:(NSUInteger)touchCount | |
{ | |
switch (touchCount) | |
{ | |
case 1: | |
return @"Single"; | |
case 2: | |
return @"Double "; | |
case 3: | |
return @"Triple "; | |
case 4: | |
return @"Quadruple "; | |
case 5: | |
return @"Quintuple "; | |
default: | |
return @""; | |
} | |
} | |
- (void)viewDidLoad | |
{ | |
[super viewDidLoad]; | |
// Do any additional setup after loading the view, typically from a nib. for (NSUInteger touchCount = 1; touchCount <= 5; touchCount++) { | |
UISwipeGestureRecognizer *vertical; | |
vertical = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(reportVerticalSwipe:)]; | |
vertical.direction = UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown; | |
//Number of fingers required | |
vertical.numberOfTouchesRequired = touchCount; | |
[self.view addGestureRecognizer:vertical]; | |
UISwipeGestureRecognizer *horizontal; | |
horizontal = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(reportHorizontalSwipe:)]; | |
horizontal.direction = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight; | |
//Number of fingers required | |
horizontal.numberOfTouchesRequired = touchCount; | |
[self.view addGestureRecognizer:horizontal]; | |
/****************************************************/ | |
//OR FOR TAPS | |
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSingleTap)]; | |
singleTap.numberOfTapsRequired = 1; | |
[self.view addGestureRecognizer:singleTap]; | |
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doDoubleTap)]; | |
doubleTap.numberOfTapsRequired = 2; | |
[self.view addGestureRecognizer:doubleTap]; | |
//In order not to fire the "singleTap" method when the user double taps the screen | |
//We'll tell it to fire up only if the doubleTap gesture fails | |
[singleTap requireGestureRecognizerToFail:doubleTap]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//This is a class that will be used by the viewcontroller where the user will make a checkmark | |
#import "CGPointUtils.h" | |
//contains declarations that are intended for use only by a subclass | |
#import <UIKit/UIGestureRecognizerSubclass.h> | |
@implementation CheckMark { | |
CGPoint lastPreviousPoint; | |
CGPoint lastCurrentPoint; | |
CGFloat lineLengthSoFar; | |
} | |
------------------------------------- | |
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event | |
{ | |
[super touchesBegan:touches withEvent:event]; | |
UITouch *touch = [touches anyObject]; | |
CGPoint point = [touch locationInView:self.view]; | |
lastPreviousPoint = point; | |
lastCurrentPoint = point; | |
lineLengthSoFar = 0.0f; | |
} | |
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event | |
{ | |
[super touchesMoved:touches withEvent:event]; | |
UITouch *touch = [touches anyObject]; | |
CGPoint previousPoint = [touch previousLocationInView:self.view]; | |
CGPoint currentPoint = [touch locationInView:self.view]; | |
CGFloat angle = angleBetweenLines(lastPreviousPoint, | |
lastCurrentPoint, | |
previousPoint, | |
currentPoint); | |
if (angle >= kMinimumCheckMarkAngle && angle <= kMaximumCheckMarkAngle && lineLengthSoFar > kMinimumCheckMarkLength) | |
{ | |
self.state = UIGestureRecognizerStateEnded; | |
} | |
lineLengthSoFar += distanceBetweenPoints(previousPoint, currentPoint); | |
lastPreviousPoint = previousPoint; | |
lastCurrentPoint = currentPoint; | |
} | |
-------------------------------------------------------- | |
//NOW IN THE VIEW CONTROLLER | |
- (void)viewDidLoad | |
{ | |
[super viewDidLoad]; | |
// Do any additional setup after loading the view, typically from a nib. | |
CheckMark *check = [[CheckMark alloc] initWithTarget:self action:@selector(doCheck:)]; | |
[self.view addGestureRecognizer:check]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//In the .h file we have to conform to the below protocol | |
//in order to allow serveral gesture recognizers to recognize gestures simultaneously | |
@interface BIDViewController : UIViewController <UIGestureRecognizerDelegate> | |
@property (strong, nonatomic) UIImageView *imageView; | |
@end | |
------------------------------------- | |
@implementation BIDViewController { | |
CGFloat scale, previousScale; | |
CGFloat rotation, previousRotation; | |
} | |
- (void)viewDidLoad | |
{ | |
[super viewDidLoad]; | |
// Do any additional setup after loading the view, typically from a nib. | |
previousScale = 1; | |
UIImage *image = [UIImage imageNamed:@"yosemite-meadows.png"]; | |
self.imageView = [[UIImageView alloc] initWithImage:image]; | |
self.imageView.userInteractionEnabled = YES; | |
self.imageView.center = CGPointMake(160, 160); | |
[self.view addSubview:self.imageView]; | |
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(doPinch:)]; | |
pinchGesture.delegate = self; | |
[self.imageView addGestureRecognizer:pinchGesture]; | |
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(doRotate:)]; | |
rotationGesture.delegate = self; | |
[self.imageView addGestureRecognizer:rotationGesture]; | |
} | |
//we always return YES to allow our pinch and rotation gestures to work together. | |
//Otherwise, the gesture recognizer that starts first would always block the other. | |
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer | |
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer | |
{ | |
return YES; | |
} | |
- (void)transformImageView | |
{ | |
CGAffineTransform t = CGAffineTransformMakeScale(scale * previousScale, | |
scale * previousScale); | |
t = CGAffineTransformRotate(t, rotation + previousRotation); | |
self.imageView.transform = t; | |
} | |
- (void)doPinch:(UIPinchGestureRecognizer *)gesture | |
{ | |
scale = gesture.scale; | |
[self transformImageView]; | |
if (gesture.state == UIGestureRecognizerStateEnded) | |
{ | |
previousScale = scale * previousScale; | |
scale = 1; | |
} | |
} | |
- (void)doRotate:(UIRotationGestureRecognizer *)gesture | |
{ | |
rotation = gesture.rotation; | |
[self transformImageView]; | |
if (gesture.state == UIGestureRecognizerStateEnded) | |
{ | |
previousRotation = rotation + previousRotation; | |
rotation = 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment