2010-05-06 5 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. 
} 

또는

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

멋지고 편리합니다. 단점이 있습니다. 일반적으로 약 10 픽셀 그들이 제스처를 인식 할 때까지 나는 그래픽 관련 앱에서 받아 들일 수 없다는 것을 알았 기 때문에 구식 방식으로 처리한다. 여러 동작을 인식하려면 더 까다 롭습니다. 상태 다이어그램을 그리는 방법을 아는 것은 많은 도움이됩니다 ... –

3

실제로 시도한 것보다 훨씬 간단합니다.

  • 보기의 기원 :

    당신은 세 개의 데이터 포인트가 필요합니다.

  • 현재 터치
  • 이전 터치

당신에 전달 된 터치 개체가 실제로 마지막 터치 위치를 포함하는 위치의 위치입니다. 따라서 당신은 그것을 추적 할 필요가 없습니다.

당신이 할 수있는 일은 두 선 사이의 각도를 계산이다 :

그리고 라디안 그 변환에 그 사용 이전 터치에

  • 원산지 현재 터치에
  • 원산지 당신의 CGAffineTransformRotate(). 귀하의 touchesMoved 처리기에서 그 모든 것을하십시오.여기

    은 단지 무엇을해야 계산하는 기능입니다 :

    에서 제프 LAMARCHE의
    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

    예 : UIGestureRecognizers 인 반면

    UITouch *touch = [touches anyObject]; 
    CGPoint origin = [view center]; 
    CGFloat angle = angleBetweenLinesInRadians(origin, [touch previousLocationInView:self.superview.superview], origin, [touch locationInView:self.superview.superview]); 
    
관련 문제