Program Tip

런타임에서 제약 조건 우선 순위를 어떻게 변경할 수 있습니까?

programtip 2020. 11. 22. 20:30
반응형

런타임에서 제약 조건 우선 순위를 어떻게 변경할 수 있습니까?


동적 높이가있는 뷰가 있고 런타임에서이 뷰 높이 우선 순위를 변경하려고합니다.

다음은 코드의 일부입니다.

if (index == 0) {

    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.priority = 1000;

} else if (index == 1) {

    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.priority = 500;

}

버튼 동작으로 인덱스를 변경하고 있습니다. 이 코드를 실행하면이 오류가 발생합니다.

*** Assertion failure in -[NSLayoutConstraint setPriority:], /SourceCache/Foundation/Foundation-1141.1/Layout.subproj/NSLayoutConstraint.m:174

여기서 내 실수는 무엇입니까?


NSLayoutConstraint클래스 참조에 명시된대로 :

우선 순위는 비 필수에서 필수로 또는 필수에서 비 필수로 변경 될 수 없습니다. NSLayoutPriorityRequiredOS X 또는 UILayoutPriorityRequirediOS의 우선 순위가 더 낮은 우선 순위로 변경되거나 제약 조건이 뷰에 추가 된 후 더 낮은 우선 순위가 필수 우선 순위로 변경 되면 예외가 발생합니다 . 제약 조건이 뷰에 설치된 후에도 하나의 선택적 우선 순위에서 다른 선택적 우선 순위로 변경할 수 있습니다.

1000 대신 우선 순위 999를 사용하십시오. 기술적으로 말하면 절대적으로 필요하지는 않지만 다른 무엇보다 우선 순위가 더 높습니다.


Cyrille의 대답에 약간의 추가를하고 싶습니다.

코드에서 제약 조건을 만드는 경우 활성화하기 전에 우선 순위를 설정해야합니다. 예를 들면 :

surveyViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self
                                               attribute:NSLayoutAttributeHeight
                                               relatedBy:NSLayoutRelationEqual
                                                  toItem:self.superview
                                               attribute:NSLayoutAttributeHeight
                                              multiplier:1
                                                constant:0];
surveyViewHeightConstraint.active = YES;
surveyViewHeightConstraint.priority = 999;

이로 인해 런타임 예외가 발생합니다.

필수에서 설치된 제약 조건에없는 우선 순위로 (또는 그 반대로) 변경하는 것은 지원되지 않습니다.

올바른 순서는 다음과 같습니다.

surveyViewHeightConstraint.priority = 999;
surveyViewHeightConstraint.active = YES;

우리가 항상 이것을 처리하는 방법은 제약 상수를 변경하지 않고 우선 순위 만 변경하는 것입니다. 예를 들어, 귀하의 상황에서 두 가지 높이 제약이 있습니다.

 heightConstraintOne (who's height is set in the storyboard at 150, and priority set at 750)
 heightConstraintTwo (who's height is set in the storyboard at 0, and priority set at 250)

보기를 숨기려면 다음을 수행하십시오.

heightConstraintTwo.priority = 999;

마찬가지로보기를 표시하려면 다음을 수행하십시오.

heightConstraintTwo.priority = 250;

Swift 버전 :

myContraint.priority = UILayoutPriority(999.0)

이 시나리오가 누군가에게 도움이되기를 바랍니다. 서로 반대되는 두 가지 제약이있었습니다. 동시에 만족할 수 없었습니다. 인터페이스 빌더에서 그중 하나는 1000 개의 우선 순위를, 다른 하나는 1000 미만의 우선 순위를 가졌습니다. 코드에서 변경했을 때이 오류가 발생했습니다.

포착되지 않은 예외 'NSInternalInconsistencyException'으로 인해 앱을 종료하는 중입니다. 이유 : '설치된 제약 조건에서 우선 순위를 필수에서 아님으로 (또는 그 반대로) 변경하는 것은 지원되지 않습니다. 우선 순위 250을 통과했고 기존 우선 순위는 1000이었습니다. '

그런 다음 .defaultHigh 및 .defaultLow 값으로 viewDidLoad 함수에서 초기화했으며 이로 인해 문제가 해결되었습니다.


NSLayoutConstraints class내부 에 따르면UIKit Module

If a constraint's priority level is less than UILayoutPriorityRequired, then it is optional. Higher priority constraints are met before lower priority constraints. Constraint satisfaction is not all or nothing. If a constraint 'a == b' is optional, that means we will attempt to minimize 'abs(a-b)'. This property may only be modified as part of initial set up or when optional. After a constraint has been added to a view, an exception will be thrown if the priority is changed from/to NSLayoutPriorityRequired.

Example:- UIButton constraints with various priorities -

 func setConstraints() {
        buttonMessage.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1.0, constant: -10).isActive = true

        let leading = NSLayoutConstraint(item: buttonMessage, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 10)

        leading.isActive = true


        let widthConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100)

        let heightConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 50)


        let trailingToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)

        trailingToSuperView.priority = 999
        trailingToSuperView.isActive = true

        //leading.isActive = false//uncomment & check it will align to right of the View

        buttonMessage.addConstraints([widthConstraint,heightConstraint])

         }  

Now you can , just take the IBOutlet connection for your constraints , then use this code .

self.webviewHeight.priority = UILayoutPriority(rawValue: 1000)

참고URL : https://stackoverflow.com/questions/31186187/how-can-i-change-constraints-priority-in-run-time

반응형