2013-04-29 2 views
13

질문에 건물은 earlier입니다.iOS : CGAffineTransformScale이 내 객체를 이동합니다.

라벨을 변형하려고하는 단순 버튼입니다. 나는 그것이 0.5만큼 줄어들 길 원한다. 그러나 그것은 어떤 이유로 작동하지만 그것도 객체를 움직인다. 레이블이 위로 이동하고 왼쪽으로 이동 한 다음 변환합니다.

- (IBAction)btnTest:(id)sender 
{ 

    [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 
     lblTest.transform = CGAffineTransformScale(lblTest.transform, 0.5f,0.5f); 
    }completion:^(BOOL finished) { 
     if(finished){ 
      NSLog(@"DONE"); 
     } 
    }]; 
} 
+1

회전에 코어 애니메이션을 사용하고 축척에 핵심 그래픽을 사용하는 이유가 있습니까? 라벨의 레이어에 스케일을 적용 해보고 도움이되는지 확인하려고합니다. –

+0

@ 0x7fffffff 방금 테스트했습니다 : 레이어에'CATransform3DMakeScale'을 적용하면 자동으로 제약 조건이 적용되지 않으므로'CGAffineTransformMakeScale'을 적용한 것처럼 보이지 않습니다. 그러나 제약 조건을 다시 적용하기 위해 무엇인가 ('setNeedsLayout' 또는'UIView' 객체에 대한 변경 사항으로 인해 제약 조건이 다시 적용될 수있는 경우) 뷰가 이동하게됩니다. 따라서 구속 조건을 다시 적용하기 전에 레이어의 변환을 아이디로 복원하면 "속속들이 들어갈"수 있지만 자동 레이아웃을 해제하거나 구속 조건을 수정하는 것이 가장 안전 할 것입니다. – Rob

답변

18

난 당신이 자동 레이아웃을 사용하고있는 질문에서 추정하고 있습니다 : 당신이 CGAffineTransformMakeScale에 따라 확장 후, 선도적 및/또는 상위 제약이있는 경우, 자동 레이아웃에서 선두/최고 구속이 될 것입니다 다시 적용하면 제약 조건이 계속 충족되도록 컨트롤이 이동하게됩니다.

당신은 (쉬운 답이있는) 자동 레이아웃을 해제 할 수 있습니다 또는 당신은 할 수 있습니다 IB에 정의 된 제약 조건이 적용, 제어가 배치되기 때문에

  • 는 대기 viewDidAppear는 (우리가 원하는 곳까지 그것과 그것의 center 재산은 신뢰할 것이다);

  • 지금 우리가 문제의 컨트롤의 center을 가지고, 다음과 같이 NSLayoutConstraintconstant을 설정 center 속성의 값을 사용하여, NSLayoutAttributeCenterXNSLayoutAttributeCenterY 제약 선두과 최고의 제약을 교체합니다.

따라서 :

// don't try to do this in `viewDidLoad`; do it in `viewDidAppear`, where the constraints 
// have already been set 

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 

    [self replaceLeadingAndTopWithCenterConstraints:self.imageView]; 
} 

// Because our gesture recognizer scales the UIView, it's quite important to make 
// sure that we don't have the customary top and leading constraints, but rather 
// have constraints to the center of the view. Thus, this looks for leading constraint 
// and if found, removes it, replacing it with a centerX constraint. Likewise if it 
// finds a top constraint, it replaces it with a centerY constraint. 
// 
// Having done that, we can now do `CGAffineTransformMakeScale`, and it will keep the 
// view centered when that happens, avoiding weird UX if we don't go through this 
// process. 

- (void)replaceLeadingAndTopWithCenterConstraints:(UIView *)subview 
{ 
    CGPoint center = subview.center; 

    NSLayoutConstraint *leadingConstraint = [self findConstraintOnItem:subview 
                  attribute:NSLayoutAttributeLeading]; 
    if (leadingConstraint) 
    { 
     NSLog(@"Found leading constraint"); 

     [subview.superview removeConstraint:leadingConstraint]; 

     [subview.superview addConstraint:[NSLayoutConstraint constraintWithItem:subview 
                     attribute:NSLayoutAttributeCenterX 
                     relatedBy:NSLayoutRelationEqual 
                     toItem:subview.superview 
                     attribute:NSLayoutAttributeTop 
                    multiplier:1.0 
                     constant:center.x]]; 
    } 

    NSLayoutConstraint *topConstraint = [self findConstraintOnItem:subview 
                 attribute:NSLayoutAttributeTop]; 

    if (topConstraint) 
    { 
     NSLog(@"Found top constraint"); 

     [subview.superview removeConstraint:topConstraint]; 

     [subview.superview addConstraint:[NSLayoutConstraint constraintWithItem:subview 
                     attribute:NSLayoutAttributeCenterY 
                     relatedBy:NSLayoutRelationEqual 
                     toItem:subview.superview 
                     attribute:NSLayoutAttributeLeft 
                    multiplier:1.0 
                     constant:center.y]]; 
    } 
} 

- (NSLayoutConstraint *)findConstraintOnItem:(UIView *)item attribute:(NSLayoutAttribute)attribute 
{ 
    // since we're looking for the item's constraints to the superview, let's 
    // iterate through the superview's constraints 

    for (NSLayoutConstraint *constraint in item.superview.constraints) 
    { 
     // I believe that the constraints to a superview generally have the 
     // `firstItem` equal to the subview, so we'll try that first. 

     if (constraint.firstItem == item && constraint.firstAttribute == attribute) 
      return constraint; 

     // While it always appears that the constraint to a superview uses the 
     // subview as the `firstItem`, theoretically it's possible that the two 
     // could be flipped around, so I'll check for that, too: 

     if (constraint.secondItem == item && constraint.secondAttribute == attribute) 
      return constraint; 
    } 

    return nil; 
} 

구현의 상세 당신이 최고의, 내 경우에는 (확장하려는 컨트롤의 제약 조건을 정의한 및 상단의베이스가 된 방법에 따라 달라질 수 있습니다 superview는 더 쉽게 만들었습니다). 그러나 바라건대 해결책을 설명하고, 이러한 제약 조건을 제거하고 중심을 기반으로 새로운 제약 조건을 추가하는 것이 좋습니다.

위에서 설명한 것처럼 문제의 제약 조건을 찾는 것을 반복하지 않으려면 대신 상단 및 선행 제약 조건에 IBOutlet을 정의하면 프로세스가 크게 단순 해집니다. 이 샘플 코드는 여러 가지 이유로 참조에 IBOutlet을 사용할 수없는 프로젝트에서 가져 왔습니다. 그러나 제약 조건에 대한 IBOutlet 참조를 사용하면 확실히 쉬운 방법입니다 (자동 레이아웃을 사용하는 경우). 당신은 인터페이스 빌더에 가면

예를 들어, 귀하 께서 어시스턴트 에디터에 문제의 제약 및 제어 - 드래그를 강조 할 수 IBOutlet :

make constraint IBOutlet

당신이 그렇게한다면, 모든 제약 조건을 반복하는 것이 아니라 다음과 같이 말할 수 있습니다.

if (self.imageViewVerticalConstraint) 
{ 
    [self.view removeConstraint:self.imageViewVerticalConstraint]; 

    // create the new constraint here, like shown above 
} 

솔직히, 나는 Interface Builder가 o 상자 밖에서 바로 이러한 제약 조건을 정의합니다 (예 : "superview의 왼쪽으로 컨트롤의 선도"제약, "superview 왼쪽에 컨트롤의 중심")보다는 IB에서 수행 할 수 있다고 생각하지 않기 때문에 프로그래밍 방식으로 제약 조건을 변경하고 있습니다. 그러나이 과정을 거치면 제어 기능을 확장 할 수 있으며 제한 사항 때문에 제어 기능을 사용할 수 없습니다.0x7fffffff가 언급 한 바와 같이 당신이 레이어에 CATransform3DMakeScale을 적용 할 경우


, 자동으로 제약 조건을 적용하지 않을 것이다, 그래서 당신은 당신이보기에 CGAffineTransformMakeScale을 적용하는 경우처럼 이동 표시되지 않습니다. 그러나 제약 조건을 다시 적용하기 위해 무엇인가를하면 (setNeedsLayout 또는 UIView 개체를 변경하면 제약 조건이 다시 적용될 수 있음)보기가 이동합니다. 따라서 구속 조건을 다시 적용하기 전에 레이어의 변환을 아이디로 복원하면 "속속들이 들어갈"수 있지만 자동 레이아웃을 해제하거나 구속 조건을 수정하는 것이 가장 안전 할 것입니다.

+0

매우 포괄적 인 답변! 감사! 나에게 모든 것을 이해하는 데 시간이 좀 걸리지 만, 대답 할 시간을내어 주셔서 감사합니다! – JoshDG

+0

매우 hepfull 대답! 너는 나의 하루를 구했다! – Amnysia

+0

방금 ​​스토리 보드에서 제약 조건을 중심으로 선행 제약 조건을 변경했지만 유사한 문제가 여전히 발생합니다. 왼쪽으로 점프하는 대신 하위 뷰가 superview의 오른쪽에 붙지 않기를 기대합니다.), 그것의 위치로 균일하게 이동하지만, 애니메이션 중에 그것은 항상 잘못된 위치에 있습니다 =/ –

관련 문제