2014-02-22 4 views
3

사용자의 터치를 사용하여 회전 및/또는 크기 조정 된 UIView를 변환하려고합니다. 나는 또한 사용자 입력으로 번역하려고합니다.회전 후 UIView 변환

- (void)handleObjectMove:(UIPanGestureRecognizer *)recognizer 
{ 
    static CGPoint lastPoint; 
    UIView *moveView = [recognizer view]; 
    CGPoint newCoord = [recognizer locationInView:playArea]; 

    // Check if this is the first touch 
    if([recognizer state]==UIGestureRecognizerStateBegan) 
    { 
     // Store the initial touch so when we change positions we do not snap 
     lastPoint = newCoord; 
    } 

    // Create the frame offsets to use our finger position in the view. 
    float dX = newCoord.x; 
    float dY = newCoord.y; 

    dX-=lastPoint.x; 
    dY-=lastPoint.y; 

    // Figure out the translation based on how we are scaled 
    CGAffineTransform transform = [moveView transform]; 
    CGFloat xScale = transform.a; 
    CGFloat yScale = transform.d; 

    dX/=xScale; 
    dY/=yScale; 

    lastPoint = newCoord; 

    [moveView setTransform:CGAffineTransformTranslate(transform, dX, dY)]; 

    [recognizer setTranslation:CGPointZero inView:playArea]; 
} 

그러나 내가 터치하고 이동하면 모든 다른 이상한 방식으로 번역됩니다. 회전 값을 사용하여 일종의 공식을 적용하여 올바르게 변환 할 수 있습니까?

+0

, 당신은 서로 회전 및/또는 스케일이 인식기에서 번역을 결합하려는 제스처 인식기 (예 : UIPinchGestureRecognizer)? – 4bar

+0

맞습니다. UIView는 번역 전에 사용자 입력에 의해 회전 및/또는 크기 조정되었습니다. 그래서 회전/스케일링을 유지하고 변환해야합니다. –

답변

2

가장 적은 양의 수학을 사용하면서 찾은 가장 좋은 해결책은 원본 번역, 회전 및 배율 값을 별도로 저장하고 변경시 변환을 다시 실행하는 것이 었습니다.

@property (nonatomic) CGPoint translation; 
@property (nonatomic) CGFloat rotation; 
@property (nonatomic) CGPoint scaling; 

그리고 다음과 같은 기능 :

- (void)rotationDelta:(CGFloat)delta 
{ 
    [self setRotation:[self rotation]+delta]; 
} 

- (void)scalingDelta:(CGPoint)delta 
{ 
    [self setScaling: 
    (CGPoint){ [self scaling].x*delta.x, [self scaling].y*delta.y }]; 
} 

- (void)translationDelta:(CGPoint)delta 
{ 
    [self setTranslation: 
    (CGPoint){ [self translation].x+delta.x, [self translation].y+delta.y }]; 
} 

- (void)transformMe 
{ 
    // Start with the translation 
    CGAffineTransform transform = CGAffineTransformMakeTranslation([self translation].x, [self translation].y); 
    // Apply scaling 
    transform = CGAffineTransformScale(transform, [self scaling].x, [self scaling].y); 
    // Apply rotation 
    transform = CGAffineTransformRotate(transform, [self rotation]); 

    [self setTransform:transform]; 
} 

- (void)setScaling:(CGPoint)newScaling 
{ 
    scaling = newScaling; 
    [self transformMe]; 
} 

- (void)setRotation:(CGFloat)newRotation 
{ 
    rotation = newRotation; 
    [self transformMe]; 
} 

- (void)setTranslation:(CGPoint)newTranslation 
{ 
    translation = newTranslation; 
    [self transformMe]; 
} 

그리고 핸들러에 다음을 사용 :

- (void)handleObjectPinch:(UIPinchGestureRecognizer *)recognizer 
{ 
    if([recognizer state] == UIGestureRecognizerStateEnded 
     || [recognizer state] == UIGestureRecognizerStateChanged) 
    { 
     // Get my stuff 
     if(!selectedView) 
      return; 

     SelectableImageView *view = selectedView; 

     CGFloat scaleDelta = [recognizer scale]; 
     [view scalingDelta:(CGPoint){ scaleDelta, scaleDelta }]; 

     [recognizer setScale:1.0]; 
    } 
} 

- (void)handleObjectMove:(UIPanGestureRecognizer *)recognizer 
{ 
    static CGPoint lastPoint; 
    SelectableImageView *moveView = (SelectableImageView *)[recognizer view]; 
    CGPoint newCoord = [recognizer locationInView:playArea]; 

    // Check if this is the first touch 
    if([recognizer state]==UIGestureRecognizerStateBegan) 
    { 
     // Store the initial touch so when we change positions we do not snap 
     lastPoint = newCoord; 
    } 

    // Create the frame offsets to use our finger position in the view. 
    float dX = newCoord.x; 
    float dY = newCoord.y; 

    dX-=lastPoint.x; 
    dY-=lastPoint.y; 
    lastPoint = newCoord; 

    [moveView translationDelta:(CGPoint){ dX, dY }]; 

    [recognizer setTranslation:CGPointZero inView:playArea]; 
} 

- (void)handleRotation:(UIRotationGestureRecognizer *)recognizer 
{ 
    if([recognizer state] == UIGestureRecognizerStateEnded 
     || [recognizer state] == UIGestureRecognizerStateChanged) 
    { 
     if(!selectedView) 
      return; 

     SelectableImageView *view = selectedView; 

     CGFloat rotation = [recognizer rotation]; 
     [view rotationDelta:rotation]; 

     [recognizer setRotation:0.0]; 
    } 
} 
+1

구조적으로는 꽤 괜찮은 것 같습니다. 또 다른 옵션은 setter 메소드에서 변환을 유효하지 않은 것으로 표시하는 플래그를 설정 한 다음, 뷰를 그리기 직전에 변환을 한 번 (유효하지 않은 경우) 업데이트합니다. 또한 더 일반적으로 배율 변경 벡터 곱하기가 아니라 곱셈을 기대할 것입니다,하지만 그것은 귀하의 응용 프로그램에 대한 훌륭한 작품. – 4bar

+0

스케일링 변경을 덧셈 대신 곱셈으로 사용하는 것이 훨씬 더 마음에 들었습니다. 그것은 곱셈으로 훨씬 잘 작동했습니다. 변경 사항을 반영하여 게시물을 업데이트했습니다. 고맙습니다! –

-1

난 내 솔루션은 다음과 같은 특성을 가진 UIView의 하위 클래스했다 나도 똑같은 문제를 겪었으니 여기를 남겨주세요.

self.view.addSubview(topView) 

그런 다음 터치에 이동하는 PanGesture 인식기를 추가 :

수익보기로 서브 뷰와 같은 평면도를 추가

//Add PanGestureRecognizer to move 
    let panMoveGesture = UIPanGestureRecognizer(target: self, action: #selector(YourViewController.moveViewPanGesture(_:))) 
    topView.addGestureRecognizer(panMoveGesture) 

을 그리고 여기에 빠른 2에서이를 수행하는 방법입니다 이동할 기능 :

//Move function 
func moveViewPanGesture(recognizer:UIPanGestureRecognizer) 
{ 
    if recognizer.state == .Changed { 
     var center = recognizer.view!.center 
     let translation = recognizer.translationInView(recognizer.view?.superview) 
     center = CGPoint(x:center.x + translation.x, 
          y:center.y + translation.y) 
     recognizer.view!.center = center 
     recognizer.setTranslation(CGPoint.zero, inView: recognizer.view) 
    } 
} 

기본적으로 하단보기 wh를 기반으로보기를 번역해야합니다. ich는 슈퍼 뷰 자체가 아닙니다. 이와 같이 : recognizer.view?.superview 또는 아래쪽보기를 회전하는 경우 다른 어떤 정보도 가지지 않을보기를 추가하고 변환하지 않는보기 (맨 아래보기)에 밑보기를 추가하고 아래쪽에보기를 추가 할 수 있습니다 그에 따라 하위보기로 봅니다. 그런 다음 맨 아래 뷰를 기반으로하여 상위 뷰를 변환해야합니다.

0

시도 대신 설정의 변경 moveView.center (x, y)에 직접 또는 하나 "CGAffineTransformTranslate"즉