[편집 : 경고 : 후속 토론 전체가 iOS 8에 의해 낡았거나 적어도 크게 완화되어 뷰 변환이 적용될 때 레이아웃을 트리거하는 실수를 더 이상하지 않을 수 있습니다.]
자동 레이아웃 vs. 뷰 변환
자동 레이아웃은 뷰 변환에서 전혀 잘 재생되지 않습니다. 내가 알 수있는 한 그 이유는 변환 (기본 ID 변환 이외)이있는 뷰의 프레임을 엉망으로 만들지 않아야하기 때문입니다. 그러나 이것이 자동 레이아웃이하는 것입니다. 자동 레이아웃이 작동하는 방식 layoutSubviews
은 런타임에서 모든 제약 조건을 따라 파싱하고 모든 뷰의 프레임을 적절하게 설정하는 것입니다.
다시 말해, 제약은 마술이 아닙니다. 그들은 단지 할 일 목록 일뿐입니다.layoutSubviews
할 일 목록이 완성되는 곳입니다. 그리고 프레임을 설정하여 수행합니다.
나는 이것을 버그로 도울 수 없다. 이 변환을 뷰에 적용하면 :
v.transform = CGAffineTransformMakeScale(0.5,0.5);
뷰가 중심과 함께 이전 크기와 절반 크기로 나타납니다. 그러나 제약 조건에 따라 내가 전혀 보지 못할 수도 있습니다.
[실제로 두 번째 놀라운 점이 있습니다. 뷰에 변환을 적용하면 레이아웃이 즉시 트리거됩니다. 이것은 나에게 또 다른 버그 인 것 같습니다. 아니면 아마도 첫 번째 버그의 핵심 일 것입니다. 내가 기대할 수있는 것은 레이아웃 시간까지 최소한 프레임 시간으로 프레임 애니메이션으로 도망 갈 수있는 것처럼 레이아웃 시간까지 장치를 회전시킬 때까지 변환으로 벗어날 수 있다는 것입니다. 그러나 실제로 레이아웃 시간은 즉각적이며 이는 잘못된 것 같습니다.]
해결 방법 1 : 제한 없음
현재 해결책 중 하나는 반영구적 변환을 뷰에 적용하고 (일시적으로 흔들리는 것이 아니라) 뷰에 영향을 미치는 모든 제약 조건을 제거하는 것입니다. 불행히도 자동 레이아웃이 여전히 발생하기 때문에 일반적으로 화면에서 뷰가 사라지고 뷰를 배치 할 위치를 알려주는 제약이 없습니다. 따라서 제약 조건을 제거하는 것 외에도보기 translatesAutoresizingMaskIntoConstraints
를 YES로 설정했습니다 . 뷰는 이제 자동 레이아웃의 영향을받지 않고 이전 방식으로 작동합니다. (그것은 됩니다 분명, 자동 레이아웃에 영향을하지만, 암시 적 자동 크기 마스크 제약의 동작이 자동 레이아웃 전과 마찬가지로 원인이 될.)
해결 방법 2 : 적절한 제약 조건 만 사용
약간 과감한 것처럼 보이면 다른 솔루션은 의도 한 변환에서 제약 조건이 올바르게 작동하도록 설정하는 것입니다. 예를 들어 뷰의 내부 고정 너비와 높이에 따라 크기가 정해지고 중심에 의해 순수하게 배치되면 스케일 변환이 예상대로 작동합니다. 이 코드에서는 하위 뷰 ( otherView
) 의 기존 제약 조건을 제거하고 해당 제약 조건을 네 가지 제약 조건으로 대체하여 너비와 높이를 고정하고 중심을 기준으로 고정합니다. 그 후 스케일 변환이 작동합니다.
NSMutableArray* cons = [NSMutableArray array];
for (NSLayoutConstraint* con in self.view.constraints)
if (con.firstItem == self.otherView || con.secondItem == self.otherView)
[cons addObject:con];
[self.view removeConstraints:cons];
[self.otherView removeConstraints:self.otherView.constraints];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:self.otherView.center.x]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:self.otherView.center.y]];
[self.otherView addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeWidth relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.width]];
[self.otherView addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeHeight relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.height]];
결론은 뷰의 프레임에 영향을 미치는 구속 조건이없는 경우 자동 레이아웃은 뷰의 프레임을 건드리지 않는다는 것입니다.
해결 방법 3 : 하위 뷰 사용
위의 두 가지 해결 방법의 문제점은 제약 조건의 이점을 잃어 시야를 확보 할 수 없다는 것입니다. 이를 해결하는 솔루션이 있습니다. 작업이 호스트 역할만을하는 보이지 않는보기로 시작하고 제약 조건을 사용하여 배치하십시오. 그 안에 실제 뷰를 하위 뷰로 넣습니다. 제약 조건을 사용하여 호스트 뷰 내에 하위 뷰를 배치 할 수 있지만 변환을 적용 할 때 반박하지 않는 제약 조건으로 제한 조건을 제한하십시오.
그림은 다음과 같습니다.
흰색보기는 호스트보기입니다. 투명하고 보이지 않는 것처럼 가장해야합니다. 빨간색 뷰는 중앙을 호스트 뷰의 중앙에 고정하여 배치 된 하위 뷰입니다. 이제 우리는 아무런 문제없이 중앙을 중심으로 빨간색보기를 확장하고 회전시킬 수 있으며 실제로 그림은 우리가 그렇게했음을 보여줍니다.
self.otherView.transform = CGAffineTransformScale(self.otherView.transform, 0.5, 0.5);
self.otherView.transform = CGAffineTransformRotate(self.otherView.transform, M_PI/8.0);
한편 호스트보기의 제약 조건은 장치를 회전 할 때 올바른 위치에 유지됩니다.
해결 방법 4 : 대신 레이어 변환 사용
뷰 변환 대신 레이아웃을 트리거하지 않으므로 구속 조건과 즉시 충돌하지 않는 레이어 변환을 사용하십시오.
예를 들어,이 간단한 "throb"뷰 애니메이션은 자동 레이아웃에서 잘릴 수 있습니다.
[UIView animateWithDuration:0.3 delay:0
options:UIViewAnimationOptionAutoreverse
animations:^{
v.transform = CGAffineTransformMakeScale(1.1, 1.1);
} completion:^(BOOL finished) {
v.transform = CGAffineTransformIdentity;
}];
결국 뷰의 크기에는 변화가 없었지만 transform
레이아웃을 설정 하면 레이아웃이 발생하고 제약 조건으로 인해 뷰가 건너 뛸 수 있습니다. (버그처럼 보입니까?) 그러나 CABasicAnimation을 사용하고 뷰 레이어에 애니메이션을 적용하는 Core Animation과 동일한 작업을 수행하면 레이아웃이 발생하지 않으며 제대로 작동합니다.
CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"transform"];
ba.autoreverses = YES;
ba.duration = 0.3;
ba.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1)];
[v.layer addAnimation:ba forKey:nil];
layerView
너비를 어떻게 알 수 있습니까? 오른쪽이 다른 것을 고집하고 있습니까?