[번역] Programmatically Creating Constraints - Advanced Auto Layout

작성일 :

개요


해당 문서는 학습 목적으로 Apple 공식 문서인 🔗 Auto Layout Guide을 번역한 글입니다. 다소 오역이 있을 수 있어 잘못된 내용이 있을 수 있습니다. 문제가 되거나 오류가 있다면 댓글 부탁드립니다.

Programmatically Creating Constraints


가능할 때마다 Interface Builder를 사용하여 제약 조건을 설정하십시오. Interface Builder는 제약 조건을 시각화, 편집, 관리 및 디버깅할 수 있는 다양한 도구를 제공합니다. 제약 조건을 분석하면 디자인 타임에 많은 일반적인 오류가 나타나므로 앱이 실행되기도 전에 문제를 찾아 수정할 수 있습니다.

Interface Builder는 계속 증가하는 작업을 관리할 수 있습니다. Interface Builder에서 거의 모든 유형의 제약 조건을 직접 작성할 수 있습니다(🔗 Working with Constraints in Interface Builder 참조). 또한 크기 클래스별 제약 조건을 지정할 수 있으며(🔗 Debugging Auto Layout 참조) 스택 뷰와 같은 새로운 도구를 사용하여 런타임에 보기를 동적으로 추가하거나 제거할 수도 있습니다(🔗 Dynamic Stack View 참조) 그러나 뷰 계층 구조에 대한 일부 동적 변경은 여전히 코드에서만 관리할 수 있습니다.

프로그래밍 방식으로 제약 조건을 생성할 때 세 가지 선택 사항이 있습니다. layout anchors를 사용하거나 🔗 NSLayoutConstraint 클래스를 사용하거나 Visual Format Language를 사용할 수 있습니다.

Layout Anchors


NSLayoutAnchor 클래스는 제약 조건을 생성하기 위한 유창한 인터페이스를 제공합니다. 이 API를 사용하려면 제한하려는 항목의 앵커 속성에 액세스하세요. 예를 들어 뷰 컨트롤러의 상단 및 하단 레이아웃 가이드에는 topAnchor, bottomAnchor 및 heightAnchor 속성이 있습니다. 반면 뷰는 가장자리, 중심, 크기 및 기준선에 대한 앵커를 노출합니다.

NOTE

iOS에서 뷰에는  🔗 layoutMarginsGuide 및  🔗 readableContentGuide 속성도 있습니다. 이러한 속성은 각각 뷰의 여백과 읽을 수 있는 콘텐츠 가이드를 나타내는 🔗 UILayoutGuide  개체를 노출합니다. 차례로 이러한 가이드는 가장자리, 중심 및 크기에 대한 앵커를 노출합니다. 프로그래밍 방식으로 여백이나 읽을 수 있는 콘텐츠 가이드에 대한 제약 조건을 만들 때 이 가이드를 사용하세요.

레이아웃 앵커를 사용하면 읽기 쉽고 압축된 형식으로 제약 조건을 만들 수 있습니다. 아래 코드 표시된 것처럼 다양한 유형의 제약 조건을 생성하기 위한 여러 메서드를 노출합니다.

swift
// Get the superview's layout
let margins = view.layoutMarginsGuide

// Pin the leading edge of myView to the margin's leading edge
myView.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true

// Pin the trailing edge of myView to the margin's trailing edge
myView.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true

// Give myView a 1:2 aspect ratio
myView.heightAnchor.constraint(equalTo: myView.widthAnchor, multiplier: 2.0).isActive = true

🔗 Anatomy of a Constraint에서 설명한 것처럼 제약 조건은 단순히 선형 방정식입니다.

image01

레이아웃 앵커에는 제약 조건을 만드는 여러 가지 방법이 있습니다. 각 방법에는 결과에 영향을 미치는 방정식 요소에 대한 매개변수만 포함됩니다. 따라서 다음 코드 줄에서:

swift
myView.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true

기호는 방정식의 다음 부분에 해당합니다.

image02

레이아웃 앵커는 또한 추가적인 유형 안전성을 제공합니다. NSLayoutAnchor 클래스에는 제약 조건을 생성하기 위한 유형 정보 및 하위 클래스별 메서드를 추가하는 여러 하위 클래스가 있습니다. 이렇게 하면 잘못된 제약 조건이 실수로 생성되는 것을 방지할 수 있습니다. 예를 들어 다른 수평 앵커로만 수평 앵커(🔗 leadingAnchor 또는 🔗 trailingAnchor)를 제한할 수 있습니다. 마찬가지로 크기 제약 조건에 대해서만 승수를 제공할 수 있습니다.

NOTE

이러한 규칙은 🔗 NSLayoutConstraint API에 의해 시행되지 않습니다. 대신 잘못된 제약 조건을 만들면 해당 제약 조건이 런타임에 예외를 발생시킵니다. 따라서 레이아웃 앵커는 런타임 오류를 컴파일 시간 오류로 변환하는 데 도움이 됩니다.

자세한 내용은  🔗 NSLayoutAnchor Class Reference 참조하세요.

NSLayoutConstraint Class


또한 🔗 NSLayoutConstraint 클래스의 🔗 constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant: 편리한 메서드를 사용하여 제약 조건을 직접 생성할 수도 있습니다. 이 방법은 명시적으로 구속 방정식을 코드로 변환합니다. 각 매개변수는 방정식의 일부에 해당합니다(🔗 The constraint equation 참조).

또한 NSLayoutConstraint 클래스의 constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant: 편리한 메서드를 사용하여 제약 조건을 직접 생성할 수도 있습니다. 이 방법은 명시적으로 구속 방정식을 코드로 변환합니다. 각 매개변수는 방정식의 일부에 해당합니다(제약 방정식 참조).

레이아웃 앵커 API에서 사용하는 접근 방식과 달리 레이아웃에 영향을 주지 않더라도 매개변수마다 값을 지정해야 합니다. 최종 결과는 일반적으로 읽기 어려운 상당한 양의 상용구 코드입니다. 예를 들어 아래 코드의 코드는 목록 위에서 설명한 코드와 기능적으로 동일합니다.

swift
NSLayoutConstraint(item: myView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = true

NSLayoutConstraint(item: myView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailingMargin, multiplier: 1.0, constant: 0.0).isActive = true

NSLayoutConstraint(item: myView, attribute: .height, relatedBy: .equal, toItem: myView, attribute:.width, multiplier: 2.0, constant:0.0).isActive = true

NOTE

레이아웃 앵커 API와 달리 편의 메서드는 특정 제약 조건의 중요한 기능을 강조 표시하지 않습니다. 결과적으로 코드를 스캔할 때 중요한 세부 정보를 놓치기 쉽습니다. 또한 컴파일러는 제약 조건의 정적 분석을 수행하지 않습니다. 유효하지 않은 제약 조건을 자유롭게 생성할 수 있습니다. 그런 다음 이러한 제약 조건은 런타임에 예외를 발생시킵니다. 따라서 iOS 8 또는 OS X v10.10 이하를 지원해야 하는 경우가 아니면 코드를 최신 레이아웃 앵커 API로 마이그레이션하는 것이 좋습니다. 자세한 내용은 *🔗 NSLayoutConstraint Class Reference*를 참조하십시오.

Visual Format Language


Visual Format Language를 사용하면 문자열과 같은 ASCII 아트를 사용하여 제약 조건을 정의할 수 있습니다. 이는 제약 조건을 시각적으로 설명하는 표현을 제공합니다. Visual Formatting Language에는 다음과 같은 장점과 단점이 있습니다.

오토 레이아웃은 Visual Format Language를 사용하여 콘솔에 제약 조건을 인쇄합니다. 이러한 이유로 디버깅 메시지는 제약 조건을 생성하는 데 사용되는 코드와 매우 유사합니다.

Visual Format Language를 사용하면 매우 간결한 표현을 사용하여 한 번에 여러 제약 조건을 만들 수 있습니다.

Visual Format Language를 사용하면 유효한 제약 조건만 만들 수 있습니다.

표기법은 완전성보다 좋은 시각화를 강조합니다. 따라서 시각적 형식 언어를 사용하여 일부 제약 조건(예: 종횡비)을 만들 수 없습니다.

컴파일러는 어떤 식으로든 문자열의 유효성을 검사하지 않습니다. 런타임 테스트를 통해서만 실수를 발견할 수 있습니다.

위에서 설명했던 코드들을 Visual Format Language를 사용하여 다시 작성해보았습니다.

swift
let views = ["myView" : myView]
let formatString = "|-[myView]-|"

let constraints = NSLayoutConstraint.constraints(withVisualFormat: formatString, options: .alignAllTop, metrics: nil, views: views)

NSLayoutConstraint.activate(constraints)

이 예에서는 leading 및 trailing 제약 조건을 모두 만들고 활성화합니다. Visual Format Language는 기본 간격을 사용할 때 항상 슈퍼뷰의 여백에 0포인트 제약 조건을 생성하므로 이러한 제약 조건은 이전 예제와 동일합니다. 그러나 위코드는 종횡비 제약을 만들 수 없습니다.

한 줄에 여러 항목이 있는 더 복잡한 보기를 만드는 경우 시각적 형식 언어는 세로 정렬과 가로 간격을 모두 지정합니다. 작성된 것처럼 "Align All Top" 옵션은 레이아웃에 영향을 미치지 않습니다. 예제에는 하나의 뷰만 있기 때문입니다(슈퍼뷰는 포함하지 않음).

시각적 형식 언어를 사용하여 제약 조건을 만들려면 다음을 수행하십시오.

  1. 뷰 Dictionary를 만듭니다. 이 Dictionary에는 값으로 키 및 뷰 객체(또는 레이아웃 가이드와 같이 자동 레이아웃에서 제한될 수 있는 다른 항목)에 대한 문자열이 있어야 합니다. 형식 문자열에서 보기를 식별하려면 키를 사용하십시오.

NOTE

Objective-C를 사용할 때 🔗 NSDictionaryOfVariableBindings 매크로를 사용하여 뷰 Dictionary를 만듭니다. Swift에서는 사전을 직접 만들어야 합니다.

  1. (Optional) metrics dictionary을 작성하십시오. 이 dictionary에는 키에 대한 문자열과 값에 대한 NSNumber 객체가 있어야 합니다. 키를 사용하여 형식 문자열에서 상수 값을 나타냅니다.
  2. 항목의 단일 행 또는 열을 배치하여 형식 문자열을 만듭니다.
  3. 🔗 NSLayoutConstraint 클래스의 🔗 constraintsWithVisualFormat:options:metrics:views: 메소드를 호출합니다. 이 메서드는 모든 제약 조건을 포함하는 배열을 반환합니다.
  4. NSLayoutConstraint 클래스의 🔗 activateConstraints: 메소드를 호출하여 제약 조건을 활성화합니다.

자세한 내용은 🔗 Visual Format Language 부록을 참조하십시오.