2010-05-06 118 views
4

我想知道什麼是在我的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; 
    } 

第二個選項對我更​​有意義,但它沒有給出令人愉快的結果(鋸齒更新和非平滑旋轉)。在性能方面哪種方式最好(如果有的話)?

乾杯!

回答

0

您考慮過使用UIRotationGestureRecognizer嗎?看起來好像已經有了邏輯,可能會讓事情變得更簡單。

+0

雖然UIGestureRecognizers是很好用,它們確實有一個缺點:它通常需要大約10個像素直到他們認出他們的手勢。我發現在我的一個與圖形相關的應用程序中是不可接受的,所以我以老式的方式來做。如果你想識別多個手勢,它會變得更加棘手。知道如何繪製狀態圖有助於很多... – 2011-04-18 20:29:05

3

它實際上比您嘗試的更簡單。

您需要三個數據點:

  • 你的觀點的由來。
  • 當前觸摸
  • 之前的觸摸

傳遞給你的觸摸對象實際上包含了最後觸摸位置的位置的位置。所以你不需要跟蹤它。

所有你需要做的就是兩條線之間計算角度:

  • 產地爲當前觸摸
  • 原產於之前的觸摸

然後將其轉換成弧度,並使用你的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]);