Online Book Reader

Home Category

iOS Recipes - Matt Drance [17]

By Root 262 0
be set to UIGestureRecognizerStateRecognized, and the delegate action selector will be called. If, at any point, a touch point is found outside the calculated bounds of the circle, the state property will be set to UIGestureRecognizerStateFailed, triggering a call to the reset method to reinitialize the process and wait for a new touch sequence.

CircleGestureRecognizer/PRPCircleGestureRecognizer.m

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

[super touchesBegan:touches withEvent:event];

if ([self numberOfTouches] != 1) {

self.state = UIGestureRecognizerStateFailed;

return;

}

self.points = [NSMutableArray array];

CGPoint touchPoint = [[touches anyObject] locationInView:self.view];

lowX = touchPoint;

lowY = lowX;

if (self.deviation == 0) self.deviation = 0.4;

moved = NO;

}

The touchesBegan:withEvent: method acts as our initializer, and the mutable array, which will hold our stored touch points, is instantiated. The first touch point is then added, and the low X and Y values are set to the current point so that they can be used later in calculating the longest line. If the deviation property has not already been set, then a default value is assigned.

CircleGestureRecognizer/PRPCircleGestureRecognizer.m

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

[super touchesMoved:touches withEvent:event];

if ([self numberOfTouches] != 1) {

self.state = UIGestureRecognizerStateFailed;

}

if (self.state == UIGestureRecognizerStateFailed) return;

CGPoint touchPoint = [[touches anyObject] locationInView:self.view];

if (touchPoint.x > highX.x) highX = touchPoint;

else if (touchPoint.x < lowX.x) lowX = touchPoint;

if (touchPoint.y > highY.y) highY = touchPoint;

else if (touchPoint.y < lowY.y) lowY = touchPoint;

[self.points addObject:[NSValue valueWithCGPoint:touchPoint]];

moved = YES;

}

The touchesMoved:withEvent: method is called for each point tracked. Multiple touches are considered invalid, and if these are identified, the state property is set to UIGestureRecognizerStateFailed. At this stage, because the circumference is not yet known, the touch point cannot yet be validated, so it is added to the points array. To calculate the diameter, the outlying points on the x- and y-axes need to be established. If the touch point exceeds one of the currently stored outliers, its value is reset to the touch point. To avoid invalidly recognizing a single point as a circle, the moved Boolean is set to YES to indicate that the touchesMoved:withEvent: method has been called at least once.

CircleGestureRecognizer/PRPCircleGestureRecognizer.m

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

[super touchesEnded:touches withEvent:event];

if (self.state == UIGestureRecognizerStatePossible) {

if (moved && [self recognizeCircle]) {

self.state = UIGestureRecognizerStateRecognized;

} else {

self.state = UIGestureRecognizerStateFailed;

}

}

}

The touchesEnded:withEvent: method needs only to check that touches have moved, and then it calls the recognizedCircle method to perform the meat of the validation.

CircleGestureRecognizer/PRPCircleGestureRecognizer.m

- (BOOL) recognizeCircle {

CGFloat tempRadius;

CGPoint tempCenter;

CGFloat xLength = distanceBetweenPoints(highX, lowX);

CGFloat yLength = distanceBetweenPoints(highY, lowY);

if (xLength > yLength) {

tempRadius = xLength/2;

tempCenter = CGPointMake(lowX.x + (highX.x-lowX.x)/2,

lowX.y + (highX.y-lowX.y)/2);

} else {

tempRadius = yLength/2;

tempCenter = CGPointMake(lowY.x + (highY.x-lowY.x)/2,

lowY.y + (highY.y-lowY.y)/2);

}

CGFloat deviant = tempRadius * self.deviation;

CGFloat endDistance =

distanceBetweenPoints([[self.points objectAtIndex:0] CGPointValue],

[[self.points lastObject] CGPointValue]);

if (endDistance > deviant*2) {

return NO;

}

for (NSValue *pointValue in self.points) {

CGPoint point = [pointValue CGPointValue];

CGFloat pointRadius = distanceBetweenPoints(point, tempCenter);

if (abs(pointRadius - tempRadius) > deviant) {

return NO;

}

}

self.radius =

Return Main Page Previous Page Next Page

®Online Book Reader