하나의 슈퍼 뷰에서 두 개의 뷰를 만든 다음 뷰간에 제약 조건을 추가했습니다.
_indicatorConstrainWidth = [NSLayoutConstraint constraintWithItem:self.view1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view2 attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f];
[_indicatorConstrainWidth setPriority:UILayoutPriorityDefaultLow];
_indicatorConstrainHeight = [NSLayoutConstraint constraintWithItem:self.view1 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view2 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f];
[_indicatorConstrainHeight setPriority:UILayoutPriorityDefaultLow];
[self addConstraint:_indicatorConstrainWidth];
[self addConstraint:_indicatorConstrainHeight];
이제 multiplier 속성을 애니메이션으로 변경하고 싶지만 multipler 속성을 변경하는 방법을 알 수 없습니다. (헤더 파일 NSLayoutConstraint.h의 개인 속성에서 _coefficient를 찾았지만 개인입니다.)
멀티플렉서 속성을 어떻게 변경합니까?
내 해결 방법은 이전 제약 조건을 제거하고에 대한 다른 값으로 새 제약 조건을 추가하는 것입니다 multipler
.
답변
적용해야 할 승수 세트가 두 개만있는 경우 iOS8 부터는 두 제약 세트를 모두 추가하고 언제든지 활성화해야 할 사항을 결정할 수 있습니다.
NSLayoutConstraint *standardConstraint, *zoomedConstraint;
// ...
// switch between constraints
standardConstraint.active = NO; // this line should always be the first line. because you have to deactivate one before activating the other one. or they will conflict.
zoomedConstraint.active = YES;
[self.view layoutIfNeeded]; // or using [UIView animate ...]
스위프트 5.0 버전
var standardConstraint: NSLayoutConstraint!
var zoomedConstraint: NSLayoutConstraint!
// ...
// switch between constraints
standardConstraint.isActive = false // this line should always be the first line. because you have to deactivate one before activating the other one. or they will conflict.
zoomedConstraint.isActive = true
self.view.layoutIfNeeded() // or using UIView.animate
답변
Swift의 NSLayoutConstraint 확장 기능은 새로운 승수 설정을 매우 쉽게 만듭니다.
스위프트 3.0 이상
import UIKit
extension NSLayoutConstraint {
/**
Change multiplier constraint
- parameter multiplier: CGFloat
- returns: NSLayoutConstraint
*/
func setMultiplier(multiplier:CGFloat) -> NSLayoutConstraint {
NSLayoutConstraint.deactivate([self])
let newConstraint = NSLayoutConstraint(
item: firstItem,
attribute: firstAttribute,
relatedBy: relation,
toItem: secondItem,
attribute: secondAttribute,
multiplier: multiplier,
constant: constant)
newConstraint.priority = priority
newConstraint.shouldBeArchived = self.shouldBeArchived
newConstraint.identifier = self.identifier
NSLayoutConstraint.activate([newConstraint])
return newConstraint
}
}
데모 사용법 :
@IBOutlet weak var myDemoConstraint:NSLayoutConstraint!
override func viewDidLoad() {
let newMultiplier:CGFloat = 0.80
myDemoConstraint = myDemoConstraint.setMultiplier(newMultiplier)
//If later in view lifecycle, you may need to call view.layoutIfNeeded()
}
답변
그만큼 multiplier
속성은 읽기 전용입니다. 이전 NSLayoutConstraint를 제거하고 새 NSLayoutConstraint를 교체하여 수정해야합니다.
그러나 승수를 변경하고 싶다는 것을 알고 있으므로 코드가 적은 변경이 필요할 때 직접 곱하여 상수를 변경할 수 있습니다.
답변
기존 레이아웃 제약 조건의 승수 를 변경하는 데 사용하는 도우미 함수 입니다. 새 구속 조건을 작성 및 활성화하고 이전 구속 조건을 비활성화합니다.
struct MyConstraint {
static func changeMultiplier(_ constraint: NSLayoutConstraint, multiplier: CGFloat) -> NSLayoutConstraint {
let newConstraint = NSLayoutConstraint(
item: constraint.firstItem,
attribute: constraint.firstAttribute,
relatedBy: constraint.relation,
toItem: constraint.secondItem,
attribute: constraint.secondAttribute,
multiplier: multiplier,
constant: constraint.constant)
newConstraint.priority = constraint.priority
NSLayoutConstraint.deactivate([constraint])
NSLayoutConstraint.activate([newConstraint])
return newConstraint
}
}
승수를 1.2로 변경하는 사용법 :
constraint = MyConstraint.changeMultiplier(constraint, multiplier: 1.2)
답변
Andrew Schreiber의 Objective-C 버전 답변
NSLayoutConstraint Class에 대한 카테고리를 작성하고 다음과 같이 .h 파일에 메소드를 추가하십시오.
#import <UIKit/UIKit.h>
@interface NSLayoutConstraint (Multiplier)
-(instancetype)updateMultiplier:(CGFloat)multiplier;
@end
.m 파일에서
#import "NSLayoutConstraint+Multiplier.h"
@implementation NSLayoutConstraint (Multiplier)
-(instancetype)updateMultiplier:(CGFloat)multiplier {
[NSLayoutConstraint deactivateConstraints:[NSArray arrayWithObjects:self, nil]];
NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:self.firstItem attribute:self.firstAttribute relatedBy:self.relation toItem:self.secondItem attribute:self.secondAttribute multiplier:multiplier constant:self.constant];
[newConstraint setPriority:self.priority];
newConstraint.shouldBeArchived = self.shouldBeArchived;
newConstraint.identifier = self.identifier;
newConstraint.active = true;
[NSLayoutConstraint activateConstraints:[NSArray arrayWithObjects:newConstraint, nil]];
//NSLayoutConstraint.activateConstraints([newConstraint])
return newConstraint;
}
@end
나중에 ViewController에서 업데이트하려는 구속 조건의 콘센트를 만듭니다.
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;
아래에서 원하는 위치에 승수를 업데이트하십시오.
self.topConstraint = [self.topConstraint updateMultiplier:0.9099];
답변
약간의 수학으로 동일한 목표를 달성하기 위해 “constant”속성을 대신 변경할 수 있습니다. 제약 조건의 기본 승수가 1.0f라고 가정합니다. 이것은 objective-c로 쉽게 번역 될 수있는 Xamarin C # 코드입니다.
private void SetMultiplier(nfloat multiplier)
{
FirstItemWidthConstraint.Constant = -secondItem.Frame.Width * (1.0f - multiplier);
}
답변
다른 답변에서 설명한 것처럼 : 제약 조건을 제거하고 새로운 제약 조건을 만들어야합니다.
전달 된 제약 조건을 다시 할당 할 수있는 NSLayoutConstraint
with inout
매개 변수에 대한 정적 메서드를 만들어 새로운 제약 조건을 반환하지 않도록 할 수 있습니다.
import UIKit
extension NSLayoutConstraint {
static func setMultiplier(_ multiplier: CGFloat, of constraint: inout NSLayoutConstraint) {
NSLayoutConstraint.deactivate([constraint])
let newConstraint = NSLayoutConstraint(item: constraint.firstItem, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: constraint.secondItem, attribute: constraint.secondAttribute, multiplier: multiplier, constant: constraint.constant)
newConstraint.priority = constraint.priority
newConstraint.shouldBeArchived = constraint.shouldBeArchived
newConstraint.identifier = constraint.identifier
NSLayoutConstraint.activate([newConstraint])
constraint = newConstraint
}
}
사용법 예 :
@IBOutlet weak var constraint: NSLayoutConstraint!
override func viewDidLoad() {
NSLayoutConstraint.setMultiplier(0.8, of: &constraint)
// view.layoutIfNeeded()
}