1

CGAffineTransform을 사용하여 프로그래밍 방식으로 willRotateToInterfaceOrientation 함수에서 회전하는 iOS 앱에 UIToolbar이 있습니다. 변환에는 스케일링, 회전 및 변환이 필요합니다. 스케일 및 회전 매개 변수를 계산하는 방법을 알고 있지만 뷰가 올바른 위치에 있도록 변환 매개 변수를 계산하는 방법을 파악하지 못하는 것 같습니다. 많은 시행 착오 끝에 iPad의 적절한 위치로보기를 이동시키기 위해 정확한 숫자를 결정했으나 코드가 너무 장치에 의존하지 않도록 숫자를 하드 코딩하지 않기를 바랍니다. 번역 매개 변수는 어떻게 계산합니까?iOS에서보기를 회전 할 때 어파 인 변환 매개 변수는 어떻게 계산합니까?

여기 내 도구 모음이 들어있는보기 컨트롤러에서 내 willRotateToInterfaceOrientation 함수입니다. 값을 하드 코딩하는 대신 txty을 계산하는 방법을 알고 싶습니다. 도구 모음 및 창 크기의 다양한 기능을 사용하여 시도했지만 도구 모음은 항상 창의 아래쪽이 아닌 이상한 위치의 창이나 창 외부에 겹쳐서 나타납니다.

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{ 
    if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) 
    { 
     // First, apply identify transformation to simplify later calculations and also because we need the toolbar's frame and Apple's docs say you cannot use a view's frame if the transform property is not the identity matrix. 
     self.toolbar.transform = CGAffineTransformIdentity; 

     // Calculate affine parameters. 

     // Expand width to the window's height when in landscape mode, leaving the toolbar's height unchanged. 
     UIWindow *window = [[UIApplication sharedApplication] keyWindow]; 
     CGFloat sx = 1.0; 
     CGFloat sy = window.frame.size.height/window.frame.size.width; 

     // Rotate 90 degrees in either direction depending on the orientation direction change. 
     CGFloat rotate = M_PI_2; 
     if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) 
     { 
      rotate = -M_PI_2; 
     } 

     // Reposition the toolbar. 
     // TODO: Calculate values rather than hard-coding them. Why is tx not something like ((window.frame.size.width/2) - (self.toolbar.frame.size.height/2))? 
     // Note that these values work for both the original iPad and iPad Retina, presumably because the values represent points not pixels. 
     CGFloat tx = -365.5; 
     CGFloat ty = 359.5; 
     if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) 
     { 
      tx = -tx; 
     } 

     // Apply affine transformation. 
     CGAffineTransform transform = CGAffineTransformMakeScale(sx, sy); 
     transform = CGAffineTransformRotate(transform, rotate); 
     transform = CGAffineTransformTranslate(transform, tx, ty); 
     [UIView animateWithDuration:duration 
         animations:^{ 
           self.toolbar.transform = transform; 
          } 
         completion:NULL 
     ]; 
    } 
    else if (toInterfaceOrientation == UIInterfaceOrientationPortrait) 
    { 
     [UIView animateWithDuration:duration 
         animations:^{ 
          self.toolbar.transform = CGAffineTransformIdentity; 
         }completion:NULL 
     ]; 
    } 
    else if (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) 
    { 
     NSLog(@"Upside-down orientation not supported"); 
    } 
} 

또한 내 툴바의 선언과 기본 초기화가 있습니다. 내 애플 리케이션은 루트보기 컨트롤러로 UITabBarController을 가지고 있기 때문에 메인 윈도우에 서브뷰로 툴바를 추가하고 수동으로 회전을 처리한다는 것을 알아 두십시오. 이것은 툴바를 탭 바 위에 표시 할 수있는 유일한 방법이었습니다.

// The toolbar is strong since this controller must maintain ownership as the toolbar is removed from the parent view when this view disappears. 
@property (strong, nonatomic) IBOutlet UIToolbar *toolbar; 

UIWindow *window = [[UIApplication sharedApplication] keyWindow]; 

CGFloat height = CGRectGetHeight(self.tabBarController.tabBar.frame); // Completely cover the tab bar. 
CGFloat x = window.frame.origin.x; 
CGFloat y = window.frame.size.height - height; 
CGFloat width = window.frame.size.width; 

self.toolbar.frame = CGRectMake(x, y, width, height); 

[window addSubview:self.toolbar]; 

마지막으로, ARC 활성화와 엑스 코드 4.5.1을 사용하고 아이 패드 (망막 및 비 망막) 5.1 및 6.0 시뮬레이터 모두 테스트입니다.

+0

응답 해 주셔서 감사합니다. 내 이해가 아닌 (CGAffineTransformMakeTranslate 대신 CGAffineTransformTranslate) 기능을 기존의 아핀 변환 주어진 된 매개 변수를 적용하여 새 변환 행렬을 구성합니다. – user19480

+0

@ user19480 당신은 완전히 틀렸어. 실수했다. 나는 그것이 Make 유형이 아니라는 사실을 놓쳤다. 사과. – WDUK

답변

2

내 도구 모음의 고정 점을 기본값 (.5, .5)에서 (0, 0)으로 설정하면이 문제를 해결할 수있었습니다. 번역이 txty 오히려 하드 코딩되지 않고 툴바 윈도우 사이즈의 함수로서 계산되는 매개 변수 여기서

// The toolbar is strong since this controller must maintain ownership as the toolbar is removed from the parent view when this view disappears. 
@property (strong, nonatomic) IBOutlet UIToolbar *toolbar; 

UIWindow *window = [[UIApplication sharedApplication] keyWindow]; 

// Set anchor point to the top-left corner instead of to the center (.5, .5) so that affine transformations during orientation changes are easier to calculate. 
self.toolbar.layer.anchorPoint = CGPointMake(0, 0); 

CGFloat height = CGRectGetHeight(self.tabBarController.tabBar.frame); // Completely cover the tab bar. 
CGFloat x = window.frame.origin.x; 
CGFloat y = window.frame.size.height - height; 
CGFloat width = window.frame.size.width; 

self.toolbar.frame = CGRectMake(x, y, width, height); 

[window addSubview:self.toolbar]; 

여기 정정 코드이다. 새로운 willRotateView:toInterfaceOrientation:duration: 함수에서 로직을 래핑하여 임의의 뷰를 재사용하고 쉽게 회전 할 수있게했습니다. willRotateToInterfaceOrientation:duration:은 내 도구 모음을 뷰 매개 변수로 사용하여이 기능으로 회전 요청을 전달합니다.

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{ 
    [self willRotateView:self.toolbar toInterfaceOrientation:toInterfaceOrientation duration:duration]; 
} 

- (void)willRotateView:(UIView *)view toInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{ 
    if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) 
    { 
     // First, apply identify transformation to simplify later calculations and also because we need the view's frame and Apple's docs say you cannot use a view's frame if the transform property is not the identity matrix. 
     view.transform = CGAffineTransformIdentity; 

     // Calculate affine parameters. 

     // Get the window's post-orientation change dimensions. 
     UIWindow *window = [[UIApplication sharedApplication] keyWindow]; 
     CGFloat rotatedWinWidth = window.frame.size.height; 
     CGFloat rotatedWinHeight = window.frame.size.width; 

     // Expand width to the window's height when in landscape mode, leaving the view's height unchanged. The scaling is done along the Y axis since the window's origin will change such that the Y axis will still run along the longer direction of the device. 
     CGFloat sx = 1.0; 
     CGFloat sy = rotatedWinWidth/rotatedWinHeight; 

     // Rotate 90 degrees in either direction depending on the orientation direction change. 
     CGFloat angle = M_PI_2; 
     if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) 
     { 
      angle = -M_PI_2; 
     } 

     // Reposition the view, assuming that view.layer.anchorPoint is (0, 0). 
     // Note that the height of the view is used as the X offset as this corresponds to the X direction since the rotated window's origin will also rotate. Also, the position has to take into account the width scale factor. 
     CGFloat xOffset = view.frame.size.height; 
     CGFloat tx = -(rotatedWinWidth - xOffset)/sy; 
     CGFloat ty = -view.frame.size.height; 
     if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) 
     { 
      tx = -xOffset/sy; 
      ty = rotatedWinHeight - view.frame.size.height; 
     } 

     // Apply affine transformation. 
     CGAffineTransform transform = CGAffineTransformMakeScale(sx, sy); 
     transform = CGAffineTransformRotate(transform, angle); 
     transform = CGAffineTransformTranslate(transform, tx, ty); 
     [UIView animateWithDuration:duration 
         animations:^{ 
          view.transform = transform; 
         } 
         completion:NULL 
     ]; 
    } 
    else if (toInterfaceOrientation == UIInterfaceOrientationPortrait) 
    { 
     [UIView animateWithDuration:duration 
         animations:^{ 
          view.transform = CGAffineTransformIdentity; 
         }completion:NULL 
     ]; 
    } 
    else if (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) 
    { 
     DLog(@"Upside-down orientation not supported"); 
    } 
} 
0

UIView 클래스 참조에서 : transform - 경계의 중심을 기준으로 수신기에 적용된 변환을 지정합니다. 즉, CGAffineTransform이 프레임 중심이 아닌 상자 중심을 중심으로 회전한다는 것을 의미합니다. 원점을 회전과의 변위를 기준으로 오프셋해야합니다. 이러한 숫자는 경계 상자의 크기에 따라 달라집니다. 당신은 당신은 당신이 회전 또는에 대한 크기 조정 무슨 자리 알아야합니다 (다윗이 언급 한 바와 같이) 당신이 일을하고 순서에 매우주의해야 CGAffineTransform와 iPhone correct landscape window coordinates

2

:

사용하여 경계의 예는 여기를 참조하십시오 . 사람들은 앵커 포인트 (당신이 아핀과 함께 회전하는 지점)에 관계없이 회전 결과에 종종 놀란다. 우리는 우리의 시작보기이 있던 경우에

는 :

original view

당신은 anchorPoint (0, 0), 또는 이미지의 중심에있을 가질 수있다. 둘 중 하나가 작동 할 수 있습니다. 혼자서도 당신이 원하는 것을 줄 수는 없습니다. 여기

는 0에서 0 : 당신은 단지 당신이 0, 0 앵커 포인트가 있다면, 당신은 회전 무슨 일이 일어난 "궁금해을 표시 할 뷰를 회전하고 싶었

rotated by 90

내 의견 !!! " 그러나 당신은 단지 당신이 원하는 곳으로 그것을 번역 할 수 있습니다.여기

이 이미지의 중심에 설정된 앵커 포인트이다

rotated about center

당신은 얻어진보기를 볼 수 있지만, 그 오프는 모두 수직 및 수평의 직사각형과 측면 다르기 때문에 길이. 원래의 높이 차이로 x를 이동하고 원래의 너비 차이로 y를 이동하여 쉽게 조정할 수 있습니다.

+0

정보 및 도움이되는 도표를 당신을 감사하십시오. 네, 뷰의 앵커 포인트를 변경해야하므로 필요한 변환 값을 계산할 수있었습니다. – user19480

+0

당신은 환영합니다. – HalR