프로그래밍 방식으로 뷰를 만들 때 자동 레이아웃 제약 조건을 설정해야하는 위치


79

제약이 설정된 다른 예를 봅니다. 일부는 viewDidLoad/ loadView(하위보기가 추가 된 후) 에 설정합니다 . 다른 사람들 updateViewConstraints은에 의해 호출되는 메서드에서 설정합니다 viewDidAppear.

제약 조건을 설정하려고 updateViewContraints하면 레이아웃이 불안정해질 수 있습니다 (예 :보기가 나타나기 전에 약간의 지연). 또한이 방법을 사용하면 기존 제약 조건을 먼저 정리해야 [self.view [removeConstraints:self.view.constraints]합니까?


1
나는 updateViewConstraints에 대해 동일한 경험을 했으므로 사용을 중단했습니다. viewDidLoad 또는 사용자 지정보기의 updateConstraints 메서드에서 제약 조건을 구성합니다. 누군가가 당신에게 확실한 답을 줄 것입니다.
bilobatum

1
updateViewConstraints: 뷰 또는 하위 뷰에 제약 조건을 추가하기 위해 하위 클래스에서이 메서드를 재정의 할 수 있습니다. (로부터 애플 문서 )
테스트

답변:


108

viewDidLoad/에 제약 조건을 설정했습니다 loadView(iOS> = 6을 타겟팅하고 있습니다). updateViewConstraints제약 조건 값을 변경하는 데 유용합니다. 예를 들어 어떤 제약 조건이 화면의 방향에 따라 달라지는 경우 (나쁜 습관입니다) constant이 방법에서 변경할 수 있습니다 .

에 제약을 추가하는 viewDidLoad것은 39:22부터 시작하는 "iOS 및 OS X 용 자동 레이아웃 소개" (WWDC 2012) 세션에서 표시됩니다. 나는 그것이 강의 중에 말한 것 중 하나라고 생각하지만 문서에 포함되지는 않습니다.

업데이트 : View Controllers의 리소스 관리에서 제약 조건 설정에 대한 언급을 발견했습니다 .

스토리 보드를 사용하는 대신 프로그래밍 방식으로 뷰를 만드는 것을 선호하는 경우 뷰 컨트롤러의 loadView 메서드를 재정의하면됩니다 . 이 메소드의 구현은 다음을 수행해야합니다.

(...)

3. 자동 레이아웃을 사용 하는 경우 방금 만든 각보기에 충분한 제한을 할당하여보기의 위치와 크기를 제어합니다 . 그렇지 않은 경우 viewWillLayoutSubviewsviewDidLayoutSubviews메서드를 구현 하여 뷰 계층 구조에서 하위 뷰의 프레임을 조정합니다. “View Controller의보기 크기 조정”을 참조하십시오.

업데이트 2 : WWDC 2015 기간 동안 애플은 새로운 설명했다updateConstraintsupdateViewConstraints권장 사용 :

실제로,이 모든 것은 뷰가 다음 레이아웃 패스를 위해 제때에 제약 조건을 변경할 수있는 기회를 제공하는 방법이지만 실제로는 필요하지 않은 경우가 많습니다.

모든 초기 제약 설정은 이상적으로 Interface Builder 내에서 발생해야합니다.

또는 제약 조건을 프로그래밍 방식으로 할당해야하는 경우 viewDidLoad와 같은 위치가 훨씬 좋습니다.

업데이트 제약은 주기적으로 반복해야하는 작업에만 해당됩니다.

또한 그렇게해야 할 필요가있을 때 제약 조건을 변경하는 것은 매우 간단합니다. 반면에 해당 로직을 관련된 다른 코드와 분리하여 나중에 실행되는 별도의 메서드로 이동하면 코드를 따르기가 훨씬 더 어려워 지므로 유지 관리가 더 어려워집니다. , 다른 사람들이 이해하기가 훨씬 더 어려울 것입니다.

그렇다면 언제 업데이트 제약을 사용해야합니까?

음, 그것은 성능으로 귀결됩니다.

제약 조건을 변경하는 것이 너무 느리다면 업데이트 제약 조건이 도움이 될 수 있습니다.

업데이트 제약 조건 내에서 제약 조건을 변경하는 것이 실제로 다른 시간에 제약 조건을 변경하는 것보다 빠릅니다.

그 이유는 엔진이이 패스에서 발생하는 모든 제약 변경 사항을 배치로 처리 할 수 ​​있기 때문입니다.


2
이것에 대한 +1이 베스트 답변입니다. Apple은 초기 제약 조건을 설정하기위한 올바른 위치로 loadView를 규정하며 updateConstraints 메서드에 추가 BOOL 플래그가 필요하지 않습니다.
awolf

4
제 생각에는 뷰가 뷰 컨트롤러가 아닌 제약에 대한 책임이 있어야한다고 생각합니다. 많은 경우에 뷰 컨트롤러는 뷰의 모든 요소가 무엇인지조차 모릅니다 (예 : 테이블 뷰 셀의 정적 레이블).
dasdom

1
@dasdom 뷰가 다른 뷰와의 관계를 어떻게 제어 할 수 있습니까? @"|-[button1]-[button2]-|"ViewController에서 와 같이 제약을 설정해야합니다 . 아니면 다른 방법이 있습니까?
Joseph

@Casper 대부분의 경우 뷰 컨트롤러의 뷰인 UIView 하위 클래스가 있습니다. 해당 뷰 내에는 하위 뷰와 하위 뷰에 대한 제약이 있습니다.
dasdom 2014 년

3
제약 조건을 변경하는 것이 왜 나쁜 습관 updateViewConstraints입니까?
테스트

33

BOOL을 만들고 -updateConstraintsUIView (또는 -updateViewConstraintsUIViewController의 경우) 에서 설정하는 것이 좋습니다 .

-[UIView updateConstraints]: (애플 문서)

제약 조건 자체를 설정하는 사용자 지정보기는이 메서드를 재정 의하여 수행해야합니다.

뷰의 수명 동안 -updateConstraints및 둘 다 -updateViewConstraints여러 번 호출 될 수 있습니다. ( setNeedsUpdateConstraints예를 들어 뷰를 호출 하면 이것이 발생하도록 트리거됩니다.) 결과적으로 BOOL을 사용하여 특정 제약 조건 설정을 한 번만 수행하거나 확인하여 중복 제약 조건을 만들고 활성화하지 않도록해야합니다. 새 제약 조건을 생성 및 활성화하기 전에 기존 제약 조건을 비활성화 / 제거합니다.

예를 들면 :

  - (void)updateConstraints {  // for view controllers, use -updateViewConstraints

         if (!_hasLoadedConstraints) {
              _hasLoadedConstraints = YES;
             // create your constraints
         }
         [super updateConstraints];
    }

Apple의 문서 super가 마지막 단계로 전화 를 권장한다고 지적한 의견에서 @fresidue를 응원 합니다. super일부 제약 조건을 변경하기 전에 호출 하면 런타임 예외 (크래시)가 발생할 수 있습니다.


7
실용적으로 차이가 있는지 확실하지 않지만 문서에는 '중요 : 구현의 마지막 단계로 [super updateConstraints] 호출'이라고 나와 있습니다.
fresidue

문서에 따르면 런타임에 뷰를 변경하고 제약 조건을 무효화하면 시스템이 즉시 해당 제약 조건을 제거하고 setNeedsUpdateConstraints를 호출합니다. 새 레이아웃이 수행되기 전에 시스템은 무효화 된 레이아웃을 사용자 정의 할 수있는 updateConstraints를 호출합니다. 따라서 시스템이 호출하는 것을 막을 수있는이 메서드에 플래그를 설정하지 않을 것입니다.
smileBot 2015 년

1
@cocoanutmobile이 답변에서 제안한대로 BOOL 플래그를 사용하는 경우 일부 제약 조건이 두 번 이상 추가되는 것을 방지하기위한 것입니다. 할 수있는 아주 좋은 일입니다. 또 다른 대안은 생성 한 제약 조건에 대한 참조를 저장 한 다음 새 제약 조건을 생성하고 활성화하기 전에 모든 제약 조건을 제거 (비활성화)하는 것입니다. 그러나이 접근 방식은 특히 이전 제약 조건과 새 제약 조건이 정확히 동일한 경우 성능이 저하됩니다.
smileyborg 2015 년

2
@cocoanutmobile 또한 여기에있는 BOOL 플래그는 시스템이 호출하는 것을 막지 않습니다 . -updateConstraints여전히 호출되고 [super updateConstraints].
smileyborg 2015 년

1
@fresidue가 언급했듯이 또는 super구현이 끝날 때 호출해야합니다 . 자세한 내용은 이 주석 을 참조하십시오. -updateConstraints-updateViewConstraints
smileyborg 2015 년

4

이것은 Apple의 WWDC 비디오 및 문서에 따라 ViewDidLoad에서 수행되어야합니다.

사람들이 updateConstraints를 추천하는 이유를 모릅니다. updateConstraints에서 수행하면 뷰가 이미 자동 마스크를 고려했기 때문에 자동 크기 조정으로 NSAutoresizingMaskLayoutConstraint에 문제가 발생합니다. 작동하려면 updateConstraints에서 제거해야합니다.

UpdateConstraints는 '업데이트'해야 할 때 초기 설정에서 변경 등을 수행해야합니다.


1
여기에서 참조하는 비디오 및 문서에 대한 링크를 추가 할 수 있습니다.
Shivam Pokhriyal

2

레이아웃 하위보기 방법을보기에서 수행하십시오.

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
}

1

스토리 보드에있는 사람들이로드되기 전에 제약 조건을 변경하는이 솔루션이 있습니다. 이 솔루션은 뷰가로드 된 후 모든 지연을 제거합니다.

-(void)updateViewConstraints{

    dispatch_async(dispatch_get_main_queue(), ^{

            //Modify here your Constraint -> Activate the new constraint and deactivate the old one

            self.yourContraintA.active = true;
            self.yourContraintB.active= false;
            //ecc..
           });

    [super updateViewConstraints]; // This must be the last thing that you do here -> if! ->Crash!
}

1

viewWillLayoutSubviews 에서도 설정할 수 있습니다 .

 override func viewWillLayoutSubviews() {

    if(!wasViewLoaded){
        wasViewLoaded = true

        //update constraint

        //also maybe add a subview            
    }
}

0

이것은 나를 위해 일했습니다.

스위프트 4.2

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

// Modify your constraints in here

  ...

}

솔직히 그만한 가치가 있는지 확실하지 않지만. viewDidLoad ()보다로드 속도가 약간 느립니다. 엄청나게 커지고 있기 때문에 후자 밖으로 옮기고 싶었습니다.


0

다음 예제는보기를 다른 클래스에 전달하는 것입니다. 스토리 보드에서 내보기 만들기

스위프트 5.0

    override func viewWillAppear(_ animated: Bool) {
        
      super.viewWillAppear(animated) 
        DispatchQueue.main.async {
            self.abcInstance = ABC(frame: self.myView.frame)
          } 
      }

 

DispatchQueue.main.async를 놓친 경우 viewWillAppear에서 제약 조건을 업데이트하는 데 시간이 걸립니다. 스토리 보드에 myView를 만들고 화면 너비 및 높이와 동일한 제약 조건을 지정한 다음 myView의 프레임을 인쇄 해보십시오. DispatchQueue.main.async 또는 viewDidAppear에 정확한 값을 제공하지만 DispatchQueue.main.async없이 viewWillAppear에 정확한 값을 제공하지 않습니다.

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