UIView 확대 축소 작업시

 if (gesture.state == UIGestureRecognizerStateBegan || gesture.state == UIGestureRecognizerStateChanged) {
        
        // 이전 scale과 gesture의 scale을 바탕으로 변위값을 계산 후 새로운 scale값을 계산함 - 최대, 최소 크기를 제한할 수 있다.

        CGFloat currentScale = [[[gesture view].layer valueForKeyPath:@"transform.scale"] floatValue];
       
        // Constants to adjust the max/min values of zoom
        const CGFloat kMaxScale = 2.0;
        const CGFloat kMinScale = 0.5;
       
        CGFloat newScale = 1 - (i_PrevScale - [gesture scale]); // new scale is in the range (0-1)
        newScale = MIN(newScale, kMaxScale / currentScale);
        newScale = MAX(newScale, kMinScale / currentScale);

        CGAffineTransform transform = CGAffineTransformScale([[gesture view] transform], newScale, newScale);
        [gesture view].transform = transform;
         
        i_PrevScale = [gesture scale]; 
        
    }

 

if (gesture.state == UIGestureRecognizerStateBegan || gesture.state == UIGestureRecognizerStateChanged) {
        
        // 이전 scale값을 바탕으로 변위값을 직접 입력하여 형태를 변환시킨다. (최대, 최소 지정 어려움)
        self.layer.transform = CATransform3DScale(self.layer.transform, gesture.scale/i_PrevScale, gesture.scale/i_PrevScale, 1);
       
        i_PrevScale = [gesture scale]; 
    }

 

UIView 회전시

if (gesture.state == UIGestureRecognizerStateBegan || gesture.state == UIGestureRecognizerStateChanged)
    { // 회전각의 변위값을 입력하여 회전시킨다.
       self.layer.transform = CATransform3DRotate(self.layer.transform, gesture.rotation-i_PrevRotation, 0, 0, 1);
        i_PrevRotation = gesture.rotation;
    }

 

if (gesture.state == UIGestureRecognizerStateBegan || gesture.state == UIGestureRecognizerStateChanged)
    { // Geusture부터 얻은 rotation 값을 직접 이력한다.
        self.transform = CGAffineTransformMakeRotation(gesture.rotation);
        i_PrevRotation = gesture.rotation;
    }

 

Button Handler 로 Zoom, Rotation 사용시

-(void) reloadButtonPoint {
    
    // 핸들러의 위치는 중점과 거리차로 scale을 구하기 때문에 반드시 원(반지름 = 뷰의 중간 길이)의 좌표내에 존재해야한다.
    
    CGPoint center = i_FrameHandler.center;

    CGFloat point = sqrtf(powf(CGRectGetMidX(self.bounds), 2.0)/2);
   
    center.x = CGRectGetMidX(self.bounds) + point;
    center.y = CGRectGetMidX(self.bounds) - point;
   
    i_FrameHandler.center = center;
}
  

/// 버튼의 Drag 이벤트 발생시 수행한다.
- (void) dragButton:(UIControl *) control withEvent: (UIEvent *) event  {
       
    CGPoint dragPoint = [[[event allTouches] anyObject] locationInView:self.superview];
    
    // 중점과 터치 포인트 간의 거리를 구하여 scale 값을 구한다.
    CGFloat distance = NaDistanceBetweenTwoPoints(self.center, dragPoint);
    CGFloat scale = distance/ CGRectGetMidX(self.bounds);
   
    if(scale >= self.minimumZoomScale && scale <= self.maximumZoomScale){
       
        [self.layer setValue:[NSNumber numberWithFloat:scale] forKeyPath:@"transform.scale"];
    }
   
    // 터치 포인트와 중점의 위치차를 구하여 아크탄젠트 값으로 angle값을 산출한다.
    CGPoint rotationPoint = CGPointZero;
   
    rotationPoint.x = dragPoint.x - self.center.x;
    rotationPoint.y = dragPoint.y - self.center.x;
   
    CGFloat  angle = atan2f(rotationPoint.y, rotationPoint.x);
   
    [self.layer setValue:[NSNumber numberWithFloat:angle] forKeyPath:@"transform.rotation.z"];
}

 

참고사항

뷰의 scale값을 지정할 때 아래의 두 방식을 사용한다.

1. 직접 key path의 값을 변경

[view.layer setValue:[NSNumber numberWithFloat:scale] forKeyPath:@"transform.scale"];

2. transform 프로퍼티 값을 계산하여 변경

view.transform = CGAffineTransformMakeScale(scale, scale);

여기에서 1번의 방법인 경우 뷰가 중첩된 상황 각각 scale값을 변경하게되면 오작동하는 경우가 발생하였다. 이럴 경우 1번과 2번 방법을 혼합하면 이런 문제를 피할수 있었다.

 

+ Recent posts