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


87

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

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

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

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

답변:


174

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

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

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


4
좋은 답변을 주셔서 감사합니다.하지만 1000 대신 999를 사용하면 높이 제한에 0을 할당하여 내 뷰를 숨길 수 없습니다.
Le'Kirdok

그것은 또 다른 문제입니다. 다른 상충되는 제약이있을 수 있습니다. 코드가 더 이상 충돌하지 않지만보기 애니메이션이 여전히 잘못된 경우이 질문을 해결됨으로 표시하십시오. 그런 다음 다른 것을 엽니 다.
Cyrille

좋은 것, 다른 값 (999, 900, 500 등)을 사용하는 것은 문제가되지 않습니다. :)
user924

7
정말? iOS 개발에서 정상적으로 작동하는 것이 있습니까? 너무 많은 일을 수동으로 수행해야하고 / 또는 시스템 버그 또는 지원되지 않는 문제를 일으키는 수많은 해결 방법 코드를 구현해야했습니다. 건설적인 의견이 아니 어서 죄송합니다.
Luten

7
이 제한은 iOS 13에서 제거 된 것 같습니다. 제약 조건을에서 required로 변경해 보았고 defaultLow작동했습니다. iOS 12에서 충돌하는 데 사용 된 것과 동일한 코드.
Steven Vandeweghe 19

53

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;

Swift 버전 4 이상

constraintName.priority = UILayoutPriority(rawValue: 999)

13

Swift 버전 :

myContraint.priority = UILayoutPriority(999.0)

8

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

 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;

5
좋습니다. 1000 대신 999를 사용
하세요

3

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

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

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


1

NSLayoutConstraints class내부 에 따르면UIKit Module

제약 조건의 우선 순위 수준이 UILayoutPriorityRequired보다 작 으면 선택 사항입니다. 더 높은 우선 순위 제한이 낮은 우선 순위 제한보다 먼저 충족됩니다. 제약 만족은 전부 또는 전부가 아닙니다. 제약 조건 'a == b'가 선택 사항이면 'abs (ab)'를 최소화하려고 시도합니다. 이 속성은 초기 설정의 일부로 또는 선택 사항 인 경우에만 수정할 수 있습니다. 제약 조건이 뷰에 추가 된 후 우선 순위가 NSLayoutPriorityRequired에서 /로 변경되면 예외가 throw됩니다.

예 :- UIButton다양한 우선 순위의 제약-

 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])

         }  

1
아니요,에서 제약 조건을 만들면 안됩니다 viewDidLayoutSubviews. 이 메서드는 여러 번 호출 될 수 있으며 중복 제약 조건을 만들면 앱이 중단 될 수 있습니다.
시속

0

나는 같은 문제에 직면했다. iOS 13에서 위에서 언급 한 답변 중 일부 변경 우선 순위가 제대로 작동하지만 iOS 12에서는 충돌이 발생합니다.

IBOutlet NSLayoutConstraint를 Storyboard의 특정 제약 조건에 대해 1000으로 유지하면서이 문제를 해결할 수있었습니다. 아래는 수정 코드입니다.

if (Condition) {
    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.isActive = false;
} else if (index == 1) {
    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.isActive = True;
}

도움이 되었기를 바랍니다!!! 건배


-2

이제 제약 조건에 대해 IBOutlet 연결을 취한 다음이 코드를 사용할 수 있습니다.

self.webviewHeight.priority = UILayoutPriority(rawValue: 1000)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.