在可可触摸中实现基于触摸的旋转
问题描述:
我想知道什么是在我的iPhone应用程序中实现基于旋转的拖拽动作的最佳方式。在可可触摸中实现基于触摸的旋转
我有一个UIView,我希望围绕它的中心旋转,当用户手指触摸视图并移动它时。把它想象成需要用手指调整的刻度盘。
的基本问题归结为:
1)我应该还记得最初的角度,改造时的touchesBegan被调用,然后每touchesMoved被调用时应用新的变换,基于当前位置的看法手指,例如,像:
- (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)如果我只是记得我最后已知的位置/角度和旋转基于对之间的角度差的观点,现在,例如, :
- (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;
}
第二个选项对我更有意义,但它没有给出令人愉快的结果(锯齿更新和非平滑旋转)。在性能方面哪种方式最好(如果有的话)?
干杯!
答
您考虑过使用UIRotationGestureRecognizer
吗?看起来好像已经有了逻辑,可能会让事情变得更简单。
答
它实际上比您尝试的更简单。
您需要三个数据点:
- 你的观点的由来。
- 当前触摸
- 之前的触摸
传递给你的触摸对象实际上包含了最后触摸位置的位置的位置。所以你不需要跟踪它。
所有你需要做的就是两条线之间计算角度:
- 产地为当前触摸
- 原产于之前的触摸
然后将其转换成弧度,并使用你的CGAffineTransformRotate()。在touchesMoved处理程序中完成所有操作。
这里是计算你需要的只是什么功能:
杰夫拉马什的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;
}
礼貌:
http://iphonedevelopment.blogspot.com/2009/12/better-two-finger-rotate-gesture.html
例子:
UITouch *touch = [touches anyObject];
CGPoint origin = [view center];
CGFloat angle = angleBetweenLinesInRadians(origin, [touch previousLocationInView:self.superview.superview], origin, [touch locationInView:self.superview.superview]);
虽然UIGestureRecognizers是很好用,它们确实有一个缺点:它通常需要大约10个像素直到他们认出他们的手势。我发现在我的一个与图形相关的应用程序中是不可接受的,所以我以老式的方式来做。如果你想识别多个手势,它会变得更加棘手。知道如何绘制状态图有助于很多... – 2011-04-18 20:29:05