Skip to content

Instantly share code, notes, and snippets.

@lamprosg
Last active May 4, 2022 16:37
Show Gist options
  • Save lamprosg/5141469 to your computer and use it in GitHub Desktop.
Save lamprosg/5141469 to your computer and use it in GitHub Desktop.
(iOS) Touches, taps and Gestures
//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
/*****************************************************/
//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];
}
}
- (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];
}
- (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 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];
}
//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