iPhone: setting required length of swipe gesture - iphone

I was wondering if there is an easy method to set the minimum swipe length, i.e. the length in pixel the user needs to swipe so that the gesture is recognised as a swipe.
I noticed that the normal swipe can be quite unresponsive (as compared to swiping photos in your photo library for instance).
This is the normal way, but I would like to reduce the required length of the swipe:
- (void)viewDidLoad
{
// SWIPING GESTURES:
UISwipeGestureRecognizer *swipeLeftRecognizer;
swipeLeftRecognizer=[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(foundLeftSwipe:)];
swipeLeftRecognizer.direction=UISwipeGestureRecognizerDirectionLeft;
//swipeRecognizer.numberOfTouchesRequired=1;
[self.view addGestureRecognizer:swipeLeftRecognizer];
[swipeLeftRecognizer release];
UISwipeGestureRecognizer *swipeRightRecognizer;
swipeRightRecognizer=[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(foundRightSwipe:)];
swipeRightRecognizer.direction=UISwipeGestureRecognizerDirectionRight;
//swipeRecognizer.numberOfTouchesRequired=1;
[self.view addGestureRecognizer:swipeRightRecognizer];
[swipeRightRecognizer release];
[super viewDidLoad];
}
#pragma mark -
#pragma mark Swipes
- (void)foundLeftSwipe:(UISwipeGestureRecognizer *)recognizer {
// do something
}
- (void)foundRightSwipe:(UISwipeGestureRecognizer *)recognizer {
// do something
}
I remember that there is a way to get the pixel start position and end position and then compare the two, but was just wondering if there is a simpler method, i.e. by simply defining a value for the minimum required swipe length in the code I have here.
EDIT:
This is how I recoded the whole thing:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
gestureStartPoint = [touch locationInView:self.view];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self.view];
CGFloat deltaXX = (gestureStartPoint.x - currentPosition.x); // positive = left, negative = right
CGFloat deltaYY = (gestureStartPoint.y - currentPosition.y); // positive = up, negative = down
CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x); // will always be positive
CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y); // will always be positive
if (deltaX >= kMinimumGestureLength && deltaY <= kMaximumVariance) {
if (deltaXX > 0) {
label.text = #"Horizontal Left swipe detected";
[self performSelector:#selector(eraseText) withObject:nil afterDelay:2];
}
else {
label.text = #"Horizontal Right swipe detected";
[self performSelector:#selector(eraseText) withObject:nil afterDelay:2];
}
}
if (deltaY >= kMinimumGestureLength && deltaX <= kMaximumVariance) {
if (deltaYY > 0) {
label.text = #"Vertical up swipe detected";
[self performSelector:#selector(eraseText) withObject:nil afterDelay:2];
}
else {
label.text = #"Vertical down swipe detected";
[self performSelector:#selector(eraseText) withObject:nil afterDelay:2];
}
}
}

I was facing the exact same thing, and I was looking for a solution. There is no such thing as required distance in UISwipeGestureRecognizer but that's not all you can use. I ended up using UIPanGestureRecognizer! It looks like a super class of swipe gesture recognizer and it certainly exposes more useful data.
There is a method available in this class called translationInView:(UIView *)aView the returns a CGPoint where x & y is the total distance over the whole pan gesture! something amazingly useful for our request! And it respects the direction by positive and negative values, meaning: y=+100 -> swipe up to down 100 points, x=+100 swipe left to right 100 points, etc...
What am I doing is to check if the user has panned for a given amount of points (I was looking for something like swipe down, so for me it was y>150) and then do my thing...
here is some code excerpts:
-(void)viewDidLoad
{
UIPanGestureRecoginzer *panDown=[[UIPanGestureRecoginzer alloc] initWithTarget:self action:#selector(swipedDown:)];
[self.view addGestureRecognizer:panDown];
}
.
.
.
-(void)swipedDown:(UIPanGestureRecoginzer *)recognizer
{
CGPoint panned=[recognizer translationInView:self.view];
if(panned.y>150){
//swiped down for 150 points
doSomething();
}
}
It also gives you the velocity of the pan: velocityInView:
Note: You should use your superview (self.view in most cases) if you want to have an overall pan effect.
Hope this helps: UIPanGestureRecognize Class Reference

Please see this documentation http://developer.apple.com/library/ios/#documentation/uikit/reference/UIResponder_Class/Reference/Reference.html
You can use touchesBegan, touchesMoved, and touchesEnded methods to find the start/end positions of the swipe. By finding the delta between the start and the end, you can get the swipe length.
Maybe something like this.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
UITouch *touch = [touches anyObject];
gestureStartPoint = [touch locationInView:self.view];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint gestureEndPoint = [touch locationInView:self.view];
// compare gestureStartPoint and gestureEndPoint to determine swipe length
}

Check out this question: UISwipeGestureRecognizer Swipe length

Swift 3:
var gestureStartPoint: CGPoint = .zero
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
gestureStartPoint = touch!.location(in: self.view)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let gestureEndPoint = touch!.location(in: self.view)
let dist = distance(gestureStartPoint, gestureEndPoint)
print(dist)
}
func distance(_ a: CGPoint, _ b: CGPoint) -> CGFloat {
let xDist = a.x - b.x
let yDist = a.y - b.y
return CGFloat(sqrt((xDist * xDist) + (yDist * yDist)))
}

Related

How to find out the touch screen position

I am developing one application. In that I am using one UIImageView and I am changing the position of the UIImageView every 0.5 seconds using below code.
[NSTimer scheduledTimerWithTimeInterval:0.5
target: self
selector:#selector(moveImage)
userInfo: nil repeats:YES];
-(void) moveImage
{
//[image1 setCenter: CGPointMake(634, 126)];
CGFloat x = (CGFloat) (arc4random() % (int) self.view.bounds.size.width);
CGFloat y = (CGFloat) (arc4random() % (int) self.view.bounds.size.height);
CGPoint squarePostion = CGPointMake(x, y);
img.center=squarePostion;
}
Now i can touch the screen. What i need to find out is my touch location and that imageview location both are correct or not.
use this
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if ([touch view] == photo1) {
//photo1 is image view give tag to it
if( photo1.tag==3)
{
NSLog(#"You have been touched image view");
}
photo1.center = touchLocation;
}
}
//it used to find the point in view
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch = [touches anyObject];
CGPoint pos = [touch locationInView: [UIApplication sharedApplication].keyWindow];
NSLog(#"%f,%f",pos.x, pos.y);
}

Move UIView with relation to touch

i'm trying to move a UIView with relation to the user's touches.
Here's what I have at the moment:
int oldX, oldY;
BOOL dragging;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (CGRectContainsPoint(window.frame, touchLocation)) {
dragging = YES;
oldX = touchLocation.x;
oldY = touchLocation.y;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (CGRectContainsPoint(window.frame, touchLocation) && dragging) {
CGRect frame;
frame.origin.x = (window.frame.origin.x + touchLocation.x - oldX);
frame.origin.y = (window.frame.origin.y + touchLocation.y - oldY);
window.frame = frame;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
dragging = NO;
}
The view keeps flickering from one location to another, and I don't know what else to do.
Any help appreciated.
What you want is to use a UIPanGestureRecognizer, introduced in iOS 3.2. You use it with something as easy as this (from your UIViewController subclass):
-(void)viewDidLoad;
{
[super viewDidLoad];
UIPanGestureRecognizer* pgr = [[UIPanGestureRecognizer alloc]
initWithTarget:self
action:#selector(handlePan:)];
[self.panningView addGestureRecognizer:pgr];
[pgr release];
}
-(void)handlePan:(UIPanGestureRecognizer*)pgr;
{
if (pgr.state == UIGestureRecognizerStateChanged) {
CGPoint center = pgr.view.center;
CGPoint translation = [pgr translationInView:pgr.view];
center = CGPointMake(center.x + translation.x,
center.y + translation.y);
pgr.view.center = center;
[pgr setTranslation:CGPointZero inView:pgr.view];
}
}
Modify the touchesBegan and touchesMoved methods to be like the following.
float oldX, oldY;
BOOL dragging;
The touchesBegan:withEvent: method.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (CGRectContainsPoint(window.frame, touchLocation)) {
dragging = YES;
oldX = touchLocation.x;
oldY = touchLocation.y;
}
}
The touchesMoved:withEvent: method.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (dragging) {
CGRect frame = window.frame;
frame.origin.x = window.frame.origin.x + touchLocation.x - oldX;
frame.origin.y = window.frame.origin.y + touchLocation.y - oldY;
window.frame = frame;
}
}
The touchesEnded:withEvent: method.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
dragging = NO;
}
Here is code in Swift, a slightly more generalist version that works with an ImageView that has been created on the screen.
let panGestureRecongnizer = UIPanGestureRecognizer(target:self, action: "handlepan:")
imageView.addGestureRecognizer(panGestureRecongnizer)
func handlepan(sender: UIPanGestureRecognizer) {
if (sender.state == UIGestureRecognizerState.Changed) {
var center = sender.view?.center
let translation = sender.translationInView(sender.view)
center = CGPointMake(center!.x + translation.x, center!.y + translation.y)
sender.view?.center = center!
sender .setTranslation(CGPointZero, inView: sender.view)
}
}
//Above answer in Swift 4.0
var dragging: Bool = false
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = event?.allTouches?.first
let touchPoint = touch?.location(in: self.window)
i
if viewToDrag.frame.contains(touchPoint!){
dragging = true
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = event?.allTouches?.first
let touchPoint = touch?.location(in: self.window)
if (dragging) {
viewToDrag.center = CGPoint(x: (touchPoint?.x)!, y: (touchPoint?.y)!)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
dragging = false
}
#PeyLoW answer is the answer I suggest and add limit to parent boundaries
-(void)handlePan:(UIPanGestureRecognizer*)pgr;
{
if (pgr.state == UIGestureRecognizerStateChanged) {
CGPoint center = pgr.view.center;
CGPoint translation = [pgr translationInView:pgr.view];
center = CGPointMake(center.x + translation.x,
center.y + translation.y);
if ([self pointInside:center withEvent:nil])
{
pgr.view.center = center;
[pgr setTranslation:CGPointZero inView:pgr.view];
}
}
}

How would I drag UITextView around the view screen?

I have a project where a UITextView (for multilines) can be dragged around the screen. So far my solution to this has been an overlay of an invisible UIButton which when dragged its center is the same as the UITextView's center.
However I've seen apps that seem to just allow the UITextView to be dragged and edited on the fly so it seems there might not be an overlay in those but I'm not sure.
Thoughts?
By the way, c in this code is the UIButton and this is how I have moved it thus far:
- (void) draggedOut: (UIControl *) c withEvent: (UIEvent *) ev
{
if(self.interfaceOrientation == UIInterfaceOrientationPortrait)
{
c.center = [[[ev allTouches] anyObject] locationInView:self.view];
AddedText.center = c.center;
}
else if(self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
c.center = [[[ev allTouches] anyObject] locationInView:self.view];
AddedText.center = c.center;
}
else if(self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
{
c.center = [[[ev allTouches] anyObject] locationInView:self.view];
AddedText.center = c.center;
}
else if(self.interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
c.center = [[[ev allTouches] anyObject] locationInView:self.view];
AddedText.center = c.center;
}
}
- (void)panTextView:(UIPanGestureRecognizer *)recognizer {
NSLog(#"panning");
location1 = [recognizer translationInView:draggableTextView];
recognizer.view.center = CGPointMake(recognizer.view.center.x + location1.x,
recognizer.view.center.y + location1.y);
[recognizer setTranslation:CGPointMake(0,0) inView:draggableTextView];
location1 =[recognizer locationInView:draggableTextView];
NSLog(#"tranlation %#",NSStringFromCGPoint(location1));
[_imgpic addSubview:recognizer.view];
appDelegate.txt=draggableTextView.text;
}
call this method after creating textview.
Well have not been able to manipulate the actual uitextview.
First tried making a button overlay that could be moved and could be pressed to start editing, but it wasn't centered properly.
Then tried the above method to move the UITextView itself. But it would only work on touches or drags. (Note this was a modified form of touchesBegan & touchesMoved)
Ended up with a UIScrollView with the UITextView as a subview. Now it can move smoothly just that it can be moved from any place on the screen. Not optimal but is the best result to thus keep everything else intact.
Does the textView need to support scrolling? If so, this could get complicated.
But if not, there are two approaches. 1) subclass the textview and override touchesBegan, touchesMoved, touchesEnded. 2) write a gesture recognizer that processes the same messages and attach it to the textview.
Here's an example of a Gesture recognizer that will do the job:
#interface TouchMoveGestureRecognizer : UIGestureRecognizer
{
CGPoint _ptOffset;
}
#end
#implementation TouchMoveGestureRecognizer
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* t = [touches anyObject];
_ptOffset = [t locationInView: self.view];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* t = [touches anyObject];
CGPoint pt = [t locationInView: self.view.superview];
pt.x -= _ptOffset.x;
pt.y -= _ptOffset.y;
CGRect r = self.view.frame;
r.origin = pt;
self.view.frame = r;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
_ptOffset = CGPointMake(-1, -1);
}
#end
and, how to use it:
- (void)viewDidLoad {
[super viewDidLoad];
_textView.scrollEnabled = NO;
TouchMoveGestureRecognizer* gr = [[[TouchMoveGestureRecognizer alloc] init] autorelease];
[_textView addGestureRecognizer: gr];
}

iPhone:Programming UISlider to position at clicked location

How to set the slider to clicked position and get the slider value on the clicked location on UISlider in iPhone programming.
i know we can drag the slider to that position but i dont want to do it. Can you please tel me how to set the slider to clicked position? Is this possible to do?
Here is the part "left as a user exercise":
- (void) tapped: (UITapGestureRecognizer*) g {
UISlider* s = (UISlider*)g.view;
if (s.highlighted)
return; // tap on thumb, let slider deal with it
CGPoint pt = [g locationInView: s];
CGFloat percentage = pt.x / s.bounds.size.width;
CGFloat delta = percentage * (s.maximumValue - s.minimumValue);
CGFloat value = s.minimumValue + delta;
[s setValue:value animated:YES];
}
The way I did it is to subclass the slider and check in touchesBegan. If the user taps on the thumb button area (which we track) then ignore the tap, but any where else on the trackbar we do:
:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
// if we didn't tap on the thumb button then we set the value based on tap location
if (!CGRectContainsPoint(lastKnownThumbRect, touchLocation)) {
self.value = self.minimumValue + (self.maximumValue - self.minimumValue) * (touchLocation.x / self.frame.size.width);
}
[super touchesBegan:touches withEvent:event];
}
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value {
CGRect thumbRect = [super thumbRectForBounds:bounds trackRect:rect value:value];
lastKnownThumbRect = thumbRect;
return thumbRect;
}
You can simply add a UITapGestureRecognizer to the slider, then pull out the UIEvent and Touches associated with it to figure out where along the UISlider the tap took place. Then set your slider's value to this calculated value.
UPDATE:
First, setup your slider and add the gesture recognizer to it.
UISlider *slider = [[[UISlider alloc] init] autorelease];
…
<slider setup>
…
UITapGestureRecognizer *gr = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(sliderTapped:)] autorelease];
[slider addGestureRecognizer:gr];
Then implement the selector
- (void)sliderTapped:(UIGestureRecognizer *)gestureRecognizer {
<left as a user excercise*>
}
*Hint: Read the docs to figure out how to get the locationInView extrapolated and figure out what the slider should be
It seems like just subclassing UISlider and returning always true to the beginTracking produce the desired effect.
iOS 10 and Swift 3
class CustomSlider: UISlider {
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
return true
}
}
I was using the subclassed UISlider code to listen to ValueChanged events in ios6> in order to implement a snap-to-grid type of function.
This was broken when upgrading to iOS7 as it no longer fired the UIControlEventsValueChanged. For anyone having the same problem it is fixed by adding a line in the if() as below:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
// if we didn't tap on the thumb button then we set the value based on tap location
if (!CGRectContainsPoint(lastKnownThumbRect, touchLocation)) {
self.value = self.minimumValue + (self.maximumValue - self.minimumValue) * (touchLocation.x / self.frame.size.width);
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
[super touchesBegan:touches withEvent:event];
}
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value {
CGRect thumbRect = [super thumbRectForBounds:bounds trackRect:rect value:value];
lastKnownThumbRect = thumbRect;
return thumbRect;
}
Hope it helps someone :)
I have used this code. Get from: http://imagineric.ericd.net/2012/11/15/uislider-touch-to-set-value/
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(sliderTapped:)];
[slider addGestureRecognizer:gr];
- (void)sliderTapped:(UIGestureRecognizer *)g {
UISlider* s = (UISlider*)g.view;
if (s.highlighted)
return; // tap on thumb, let slider deal with it
CGPoint pt = [g locationInView: s];
CGFloat percentage = pt.x / s.bounds.size.width;
CGFloat delta = percentage * (s.maximumValue - s.minimumValue);
CGFloat value = s.minimumValue + delta;
[s setValue:value animated:YES];
}
Hope this can help you.

Implementing touch-based rotation in cocoa touch

I am wondering what is the best way to implement rotation-based dragging movements in my iPhone application.
I have a UIView that I wish to rotate around its centre, when the users finger is touch the view and they move it. Think of it like a dial that needs to be adjusted with the finger.
The basic question comes down to:
1) Should I remember the initial angle and transform when touchesBegan is called, and then every time touchesMoved is called apply a new transform to the view based on the current position of the finger, e.g., something like:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self]; //current position of touch
if (([touch view] == self)
&& [Utility getDistance:currentPoint toPoint:self.middle] <= ROTATE_RADIUS //middle is centre of view
&& [Utility getDistance:currentPoint toPoint:self.middle] >= MOVE_RADIUS) { //will be rotation gesture
//remember state of view at beginning of touch
CGPoint top = CGPointMake(self.middle.x, 0);
self.initialTouch = currentPoint;
self.initialAngle = angleBetweenLines(self.middle, top, self.middle, currentPoint);
self.initialTransform = self.transform;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self]; //current position of touch
if (([touch view] == self)
&& [Utility getDistance:currentPoint toPoint:self.middle] <= ROTATE_RADIUS
&& [Utility getDistance:currentPoint toPoint:self.middle] >= MOVE_RADIUS) { //a rotation gesture
//rotate tile
float newAngle = angleBetweenLines(self.middle, CGPointMake(self.middle.x, 0), self.middle, currentPoint); //touch angle
float angleDif = newAngle - self.initialAngle; //work out dif between angle at beginning of touch and now.
CGAffineTransform newTransform = CGAffineTransformRotate(self.initialTransform, angleDif); //create new transform
self.transform = newTransform; //apply transform.
}
OR
2) Should I simply remember the last known position/angle, and rotate the view based on the difference in angle between that and now, e.g.,:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self]; //current position of touch
if (([touch view] == self)
&& [Utility getDistance:currentPoint toPoint:self.middle] <= ROTATE_RADIUS
&& [Utility getDistance:currentPoint toPoint:self.middle] >= MOVE_RADIUS) { //will be rotation gesture
//remember state of view at beginning of touch
CGPoint top = CGPointMake(self.middle.x, 0);
self.lastTouch = currentPoint;
self.lastAngle = angleBetweenLines(self.middle, top, self.middle, currentPoint);
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self]; //current position of touch
if (([touch view] == self)
&& [Utility getDistance:currentPoint toPoint:middle] <= ROTATE_RADIUS
&& [Utility getDistance:currentPoint toPoint:middle] >= MOVE_RADIUS) { //a rotation gesture
//rotate tile
float newAngle = angleBetweenLines(self.middle, CGPointMake(self.middle.x, 0), self.middle, currentPoint); //touch angle
float angleDif = newAngle - self.lastAngle; //work out dif between angle at beginning of touch and now.
CGAffineTransform newTransform = CGAffineTransformRotate(self.transform, angleDif); //create new transform
self.transform = newTransform; //apply transform.
self.lastTouch = currentPoint;
self.lastAngle = newAngle;
}
The second option makes more sense to me, but it is not giving very pleasing results (jaggy updates and non-smooth rotations). Which way is best (if any), in terms of performance?
Cheers!
It is actually much simpler than what you have tried.
You need three data points:
The origin of your view.
The location of the current touch
The location of the previous touch
The Touch object passed to you actually contains the last touch location. So you don't need to keep track of it.
All you have to do is calculate the angle between two lines:
Origin to Current Touch
Origin to Previous Touch
Then convert that to radians and use that in your CGAffineTransformRotate(). Do that all in your touchesMoved handler.
Here is a function to calculate what you need just that:
static inline CGFloat angleBetweenLinesInRadians(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPoint line2End) {
CGFloat a = line1End.x - line1Start.x;
CGFloat b = line1End.y - line1Start.y;
CGFloat c = line2End.x - line2Start.x;
CGFloat d = line2End.y - line2Start.y;
CGFloat line1Slope = (line1End.y - line1Start.y) / (line1End.x - line1Start.x);
CGFloat line2Slope = (line2End.y - line2Start.y) / (line2End.x - line2Start.x);
CGFloat degs = acosf(((a*c) + (b*d)) / ((sqrt(a*a + b*b)) * (sqrt(c*c + d*d))));
return (line2Slope > line1Slope) ? degs : -degs;
}
Courtesy of Jeff LaMarche at:
http://iphonedevelopment.blogspot.com/2009/12/better-two-finger-rotate-gesture.html
Example:
UITouch *touch = [touches anyObject];
CGPoint origin = [view center];
CGFloat angle = angleBetweenLinesInRadians(origin, [touch previousLocationInView:self.superview.superview], origin, [touch locationInView:self.superview.superview]);
Have you considered using UIRotationGestureRecognizer? Seems like that has the logic already baked in, and might make things simpler.