이 글은 Auto Layout Guide: Anatomy of a Constraint 문서를 번역한 글입니다.
학습을 위해 일부 내용을 첨삭하여 원문과 동일하지 않을 수 있습니다.

뷰 계층 구조의 레이아웃은 일련의 선형 방정식으로 정의된다. 각 제약은 단일 방정식을 나타낸다.

img1

이 제약 조건은 빨간색 뷰의 선행 가장자리가 파란색 뷰의 후행 가장자리 이후 8.0 포인트여야 함을 나타낸다. 방정식에는 여러 부분이 있다.

  • Item 1 → 방정식의 첫번째 항목(이 경우 RedView)이다. 항목은 뷰 또는 Layout Guide 이어야 한다.
  • Attribute 1 → 첫번째 항목(이 경우 RedView의 Leading)에 제한될 속성이다.
  • Relationship → 왼쪽과 오른쪽 사이의 관계. 관계는 같음, 크거나 같음, 작거나 같음의 세 가지 값 중 하나를 가질 수 있다. 이 경우 왼쪽과 오른쪽이 동일하다.
  • Multiplier → Attribute 2의 값에 이 부동 소수점 수를 곱한다. 이 경우 Multiplier는 1.0 이다.
  • Item 2 → 방정식의 두번째 항목(이 경우 BlueView)이다. 첫번째 항목과 달리 비워둘 수 있다.
  • Attribute 2 → 두번째 항목(이 경우 BlueView의 Trailing)에 제한될 속성이다. 두번째 항목이 비어있으면 이 값은 Not an Attribute 이어야 한다.
  • Constant → 상수 부동 소수점 오프셋 (이 경우 8.0) 이 값은 Attribute 2의 값에 추가된다.

대부분의 제약은 사용자 인터페이스에서 두 항목 간의 관계를 정의한다. 이러한 항목은 뷰 또는 Layout Guide을 나타낼 수 있다. 제약 조건은 단일 항목의 서로 다른 두 속성 간의 관계를 정의 할 수도 있다. (예: 항목의 높이와 너비 사이의 종횡비 설정). 항목의 높이 또는 너비에 상수 값을 할당 할 수도 있다. 상수 값으로 작업할 때 두번째 항목은 비워두고 두번째 속성은 Not An Attribute로 설정되며 Constant는 0.0으로 설정된다.

오토 레이아웃 속성

오토 레이아웃에서 속성은 제한 될 수 있는 기능을 정의한다. 일반적으로 여기에는 높이, 너비, 수직 및 수평 중심뿐만 아니라 네 개의 모서리(leading, trailing, top, bottom)가 포함된다. 텍스트 항목에는 하나 이상의 기본 속성이 있다.

img2

샘플 방정식

이러한 방정식에 사용할 수있는 광범위한 매개 변수 및 속성을 통해 다양한 유형의 제약 조건을 생성 할 수 있다. 뷰 사이의 공간을 정의하고, 뷰의 가장자리를 정렬하고, 두 뷰의 상대적 크기를 정의하거나 뷰의 종횡비를 정의 할 수도 있다. 그러나 모든 속성이 호환되는 것은 아니다.

속성에는 두 가지 기본 유형이 있다. 크기 속성 (예 : Height 및 Width) 및 위치 속성 (예 : Leading, Left 및 Top). 크기 속성은 위치를 표시하지 않고 항목의 크기를 지정하는 데 사용된다. 위치 속성은 다른 항목과 관련된 항목의 위치를 지정하는 데 사용된다. 그러나 항목의 크기에 대한 표시는 없다.

이러한 차이점을 염두에두고 다음 규칙이 적용된다.

  • 크기 속성을 위치 속성으로 제한 할 수 없다.
  • 위치 속성에는 상수 값을 할당 할 수 없다.
  • 위치 속성에는 비식별 multiplier (1.0 이외의 값)를 사용할 수 없다.
  • 위치 속성의 경우 수직 속성을 수평 속성으로 제한 할 수 없다.
  • 위치 속성의 경우 Leading 또는 Trailing 속성을 왼쪽 또는 오른쪽 속성으로 제한 할 수 없다.

예를 들어 항목의 Top을 상수 값 20.0으로 설정하는 것은 추가 컨텍스트 없이는 의미가 없다. 항상 다른 항목과 관련하여 항목의 위치 속성을 정의해야한다 (예 : 수퍼 뷰의 상단 아래 20.0 포인트). 그러나 항목의 높이를 20.0으로 설정하는 것은 완벽하게 유효한다.

// Setting a constant height
View.height = 0.0 * NotAnAttribute + 40.0

// Setting a fixed distance between two buttons
Button_2.leading = 1.0 * Button_1.trailing + 8.0

// Aligning the leading edge of two buttons
Button_1.leading = 1.0 * Button_2.leading + 0.0

// Give two buttons the same width
Button_1.width = 1.0 * Button_2.width + 0.0

// Center a view in its superview
View.centerX = 1.0 * Superview.centerX + 0.0
View.centerY = 1.0 * Superview.centerY + 0.0

// Give a view a constant aspect ratio
View.height = 2.0 * View.width + 0.0

할당이 아닌 평등

방정식은 할당이 아닌 평등을 나타낸다.

오토 레이아웃이 이러한 방정식을 풀 때 오른쪽의 값을 왼쪽에 할당하는 것이 아니다. 대신 관계를 true로 만드는 속성 1과 속성 2의 값을 계산한다. 즉, 방정식의 항목을 자유롭게 재정렬 할 수 있다. 예를 들어, 목록 3-2의 방정식은 Note의 해당 방정식과 동일하다.

// Setting a fixed distance between two buttons
Button_1.trailing = 1.0 * Button_2.leading - 8.0

// Aligning the leading edge of two buttons
Button_2.leading = 1.0 * Button_1.leading + 0.0

// Give two buttons the same width
Button_2.width = 1.0 * Button.width + 0.0

// Center a view in its superview
Superview.centerX = 1.0 * View.centerX + 0.0
Superview.centerY = 1.0 * View.centerY + 0.0

// Give a view a constant aspect ratio
View.width = 0.5 * View.height + 0.0

항목을 재정렬할 때 multiplier와 constant를 반전해야 한다. 예를 들어 constant 8.0은 -8.0의 multiplier의 승수 2.0는 0.5이다. constant 0.0과 multiplier 1.0은 변경하지 않는다.

오토 레이아웃은 동일한 문제를 해결하는 여러 가지 방법을 제공한다. 이상적으로는 의도를 가장 명확하게 설명하는 솔루션을 선택해야 한다. 그러나 다른 개발자는 의심할 여지없이 어떤 솔루션이 가장 좋은지에 대해 동의하지 않을 것이다. 여기서 일관성이 있는 것이 옳은 것보다 낫다. 접근 방식을 선택하고 항상 이를 고수한다면 장기적으로 문제를 덜 경험하게 될 것이다. 예를 들어 이 가이드에서는 다음과 같은 경험 규칙을 사용한다.

  1. 분수 multiplier보다 정수 multiplier가 선호된다.
  2. 음의 constant보다 양의 constant가 선호된다.
  3. 가능한 경우 뷰는 레이아웃 순서로 나타나야한다: leading to trailing, top to bottom

모호하지 않고 만족스러운 레이아웃 만들기

이 부분은 개념보다 직접적인 실습이 주를 이루고 있어 건너뜀

제약 불평등

지금까지 모든 샘플에서 제약 조건이 동등함을 보여주었지만 이것은 이야기의 일부일뿐이다. 제약은 불평등을 나타낼수도 있다. 특히 제약 조건의 관계는 같거나, 크거나 같거나, 작거나 같을 수 있다.

예를 들어 제약 조건을 사용하여 뷰의 최소 또는 최대 크기를 정의할 수 있다.

// Setting the minimum width
View.width >= 0.0 * NotAnAttribute + 40.0

// Setting the maximum width
View.width <= 0.0 * NotAnAttribute + 280.0

As soon as you start using inequalities, the two constraints per view per dimension rule breaks down. 항상 단일 같음 관계를 두 개의 부등식으로 바꿀 수 있다.

// A single equal relationship
Blue.leading = 1.0 * Red.trailing + 8.0

// Can be replaced with two inequality relationships
Blue.leading >= 1.0 * Red.trailing + 8.0
Blue.leading <= 1.0 * Red.trailing + 8.0

두 부등식이 항상 단일 같음 관계와 같지는 않기 때문에 그 반대가 항상 참은 아니다. 예를 들어 목록 3-3의 부등식은 뷰의 너비에 대해 가능한 값의 범위를 제한하지만 그 자체로는 너비를 정의하지 않는다. 이 범위 내에서 뷰의 위치와 크기를 정의하려면 추가 수평 제약 조건이 필요하다.

제약 우선 순위

기본적으로 모든 제약 조건이 필요하다. 오토 레이아웃은 모든 제약 조건을 충족하는 솔루션을 계산해야 한다. 그렇지 않으면 오류가 있다. 오토 레이아웃은 만족할 수 없는 제약 조건에 대한 정보를 콘솔에 인쇄하고 중단할 제약 조건 중 하나를 선택한다. 그런 다음 제약 조건이 깨지지 않고 솔루션을 다시 계산한다.

선택적 제약 조건을 만들 수도 있다. 모든 제약 조건은 1에서 1000 사이의 우선 순위를 갖는다. 우선 순위가 1000인 제약 조건이 필요하다. 다른 모든 제약은 선택 사항이다.

솔루션을 계산할 때 오토 레이아웃은 가장 높은 순서에서 가장 낮은 순서로 모든 제약 조건을 충족하려고 한다. 선택적 제약 조건을 충족할 수 없는 경우 해당 제약 조건을 건너뛰고 다음 제약 조건으로 계속 진행한다.

선택적 제약 조건을 충족할 수 없더라도 레이아웃에 영향을 미칠 수 있다. 제약 조건을 건너 뛴 후 레이아웃에 모호성이 있으면 시스템은 제약 조건에 가장 가까운 솔루션을 선택한다. 이런식으로 만족스럽지않은 선택적 제약은 뷰를 끌어당기는 힘으로 작용한다.

선택적 제약과 불평등은 종종 함께 작동한다. 예를 들어, 목록 3-4에서 두 부등식에 대해 다른 우선 순위를 제공할 수 있다. 크거나 같음 관계가 필요할 수 있으며 (우선 순위 1000), 작거나 같음 관계의 우선 순위가 더 낮다 (우선 순위 250). 이는 파란색 뷰가 빨산색 뷰에서 8.0 포인트보다 가까울 수 없음을 의미한다. 그러나 다른 제약으로 인해 더 멀리 떨어질 수 있다. 그래도 선택적 제약 조건은 레이아웃의 다른 제약 조건이 주어졌을 때 파란색 뷰를 빨간색 뷰쪽으로 당겨 가능한 8.0 포인트 간격에 가깝게 만든다.

고유 콘텐츠 크기

지금까지 모든 예제는 제약 조건을 사용하여 뷰의 위치와 크기를 모두 정의했다. 그러나 일부 뷰는 현재 콘텐츠를 고려할 때 자연스러운 크기를 갖는다. 이를 고유 콘텐츠 크기라고 한다. 예를 들어 버튼의 고유 콘텐츠 크기는 제목 크기에 작은 여백을 더한 것이다.

모든 뷰에 고유 콘텐츠 크기가 있는 것은 아니다. 그렇게 하는 뷰의 경우 내장 콘텐츠 크기는 뷰의 높이, 너비 또는 둘 다를 정의 할 수 있다. 표 3-1에는 몇 가지 예가 나열되어 있다.

고유 콘텐츠 크기
UIView, NSView 본질적인 콘텐츠 크기가 없음
슬라이더 너비(iOS)만 정의한다. 슬라이더의 유형(OS X)에 따라 너비, 높이 또는 둘 다를 정의한다.
레이블, 버튼, 스위치 및 텍스트 필드 높이와 너비를 모두 정의한다.
텍스트뷰 및 이미지뷰 고유 콘텐츠 크기는 다를 수 있다.

기본 콘텐츠 크기는 뷰의 현재 콘텐츠를 기반으로 한다. 레이블 또는 버튼의 고유 콘텐츠 크기는 표시되는 텍스트의 양과 사용된 글꼴을 기반으로 한다. 다른 뷰의 경우 고유 콘텐츠 크기가 훨씬 더 복잡하다. 예를 들어, 빈 이미지 뷰에는 고유 콘텐츠 크기가 없다. 하지만 이미지를 추가하자자마 고유 콘텐츠 크기가 이미지 크기로 설정된다.

텍스트뷰의 고유 콘텐츠 크기는 콘텐츠, 스크롤 사용 여부 및 뷰에 적용된 다른 제약 조건에 따라 다르다. 예를 들어 스크롤이 활성화된 경우 뷰에 고유 콘텐츠 크기가 없다. 스크롤을 사용하지 않으면 기본적으로 뷰의 고유 콘텐츠 크기는 줄바꿈없이 텍스트 크기를 기준으로 계산된다. 예를 들어, 텍스트에 리턴이 없는 경우 콘텐츠를 한 줄의 텍스트로 레이아웃하는데 필요한 높이와 너비를 계산한다. 뷰의 너비를 지정하기 위해 제약 조건을 추가하는 경우 기본 콘텐츠 크기는 너비가 지정된 텍스트를 표시하는 데 필요한 높이를 정의한다.

오토 레이아웃은 각 차원에 대한 한 쌍의 제약 조건을 사용하여 뷰의 고유 콘텐츠 크기를 나타낸다. content hugging은 뷰를 안쪽으로 당겨 콘텐츠 주변에 꼭 맞도록 한다. content compression은 콘텐츠를 자르지 않도록 뷰를 바깥쪽으로 밀어낸다.

img3

이러한 제약은 목록 3-5에 표시된 부등식을 사용하여 정의된다. 여기서 IntrinsicHeightIntricsicWidth 상수는 뷰의 고유 콘텐츠 크기에서 높이 및 너비 값을 나타낸다.

// Compression Resistance
View.height >= 0.0 * NotAnAttribute + IntrinsicHeight
View.width >= 0.0 * NotAnAttribute + IntrinsicWidth

// Content Hugging
View.height <= 0.0 * NotAnAttribute + IntrinsicHeight
View.width <= 0.0 * NotAnAttribute + IntrinsicWidth

이러한 제약은 각각 고유한 우선 순위를 가질 수 있다. 기본적으로 뷰는 content hugging에 250 우선 순위를 사용하고 compression resistance에 750 우선 순위를 사용한다. 따라 뷰를 축소하는 것보다 늘리는 것이 더 쉽다. 대부분의 컨트롤러에서 이것이 바람직한 동작이다. 예를 들어 기본 콘텐츠 크기보다 큰 버튼을 안전하게 늘릴 수 있다. 그러나 축소하면 내용이 잘릴 수 있다. Interface Builder는 관계를 방지하기 위해 때때로 이러한 우선 순위를 수정할 수 있다.

가능하면 레이아웃에서 뷰의 고유 콘텐츠 크기를 사용하는 것이 좋다. 뷰의 콘텐츠가 변경되면 레이아웃이 동적으로 조정된다. 또한 모호하지 않고 충돌하지 않는 레이아웃을 생성하는 데 필요한 제약의 수를 줄이지만 뷰의 콘텐츠 포옹 및 압축 저항(CHCR) 우선 순위를 관리해야한다. 다음은 고유 콘텐츠 크기를 처리하기 위한 몇가지 지침이다.

  • 일련의 뷰를 확장하여 공간을 채울 때 모든 뷰의 content hugging 우선 순위가 동일하면 레이아웃이 모호하다. 오토 레이아웃은 어떤 뷰를 늘려야하는지 알지 못한다.
    일반적인 예는 레이블 및 텍스트 필드 쌍이다. 일반적으로 레이블이 고유 콘텐츠 크기로 유지되는 동안 추가 공간을 채우기 위해 텍스트 필드를 늘려야한다. 이를 확인하려면 텍스트 필드의 가로 content hugging 우선 순위가 레이블보다 낮은지 확인한다.
    실제로 이 예제는 매우 일반적이어서 Interface Builder가 자동으로 이를 처리하여 모든 레이블의 content hugging 우선 순위를 251로 설정한다. 프로그래밍 방식으로 레이아웃을 만드는 경우 content hugging 우선 순위를 직접 수정해야 한다.
  • 보이지 않는 배경(예: 버튼 또는 레이블)이 있는 뷰가 원래 콘텐츠 크기를 넘어서 실수로 늘어난 경우 이상하고 예기치 않은 레이아웃이 종종 발생한다. 텍스트가 잘못된 위치에 표시되기 때문에 실제 문제가 명확하지 않을 수 있다.
    원하지 않는 확장을 방지하려면 content hugging 우선 순위를 높이면 된다.
  • 기준선 제약 조건은 고유 콘텐츠 높이에 있는 뷰에서만 작동한다. 뷰가 수직으로 늘어나거나 압축되면 기준선 구속 조건이 더 이상 제대로 정렬되지 않는다.
  • 스위치와 같은 일부 뷰는 항상 고유 콘텐츠 크기로 표시되어야한다. 스트레칭 또는 압축을 방지하기 위해 필요에 따라 CHCR 우선 순위를 높인다.
  • 뷰에 필요한 CHCR 우선 순위를 제공하면 안된다. 일반적으로 뷰의 크기가 잘못된 것이 우연히 충돌을 일으키는 것보다 낫다. 뷰가 항상 고유 콘텐츠 크기여야하는 경우 대신 매우 높은 우선 순위(999)를 사용하는 것이 좋다. 이 접근 방식은 일반적으로 뷰가 늘어나거나 압축되지 않도록 하지만 예상보다 크거나 작은 환경에서 뷰가 표시되는 경우에 대비하여 여전히 비상 압력 밸브를 제공한다.

고유 콘텐츠 크기 대 피팅 크기

고유 콘텐츠 크기는 오토 레이아웃에 대한 입력 역할을 한다. 뷰에 고유 콘텐츠 크기가 있는 경우 시스템은 해당 크기를 나타내는 제약 조건을 생성하고 제약 조건을 사용하여 레이아웃을 계산한다.

반면에 피팅 크기는 오토 레이아웃 엔진의 출력입니다. 뷰의 제약 조건을 기반으로 뷰에 대해 계산된 크기이다. 뷰가 오토 레이아웃을 사용하여 하위 뷰를 레이아웃하는 경우 시스템은 해당 내용을 기반으로 뷰에 맞는 크기를 계산할 수 있다.

스택뷰가 좋은 예다. 다른 제약 조건을 제외하고 시스템은 콘텐츠 및 속성을 기반으로 스택 뷰의 크기를 계산한다. 여러면에서 스택 뷰는 고유한 콘텐츠 크기가 있는 것처럼 작동한다. 단일 수직 및 단일 수평 제약 조건 만 사용하여 위치를 정의하는 유효한 레이아웃을 만들 수 있다. 그러나 크기는 오토 레이아웃에 의해 계산되며 오토 레이아웃에 대한 입력이 아니다. 스택뷰에는 고유 콘텐츠 크기가 없기 때문에 스택뷰의 CHCR 우선 순위를 설정해도 효과가 없다.

스택뷰 외부의 항목을 기준으로 스택뷰의 피팅 크기를 조정해야하는 경우 해당 관계를 캡처하기 위한 명시적 제약 조건을 생성하거나 스택 외부 항목에 대한 스택 콘텐츠의 CHCR 우선 순위를 수정한다.

가치 해석

오토 레이아웃의 값은 항상 포인트 단위이다. 그러나 이러한 측정의 정확한 의미는 관련된 속성과 뷰의 레이아웃 방향에 따라 달라질 수 있다.

Auto Layout Attributes Value Notes
Height, Width 뷰의 크기 이러한 속성은 상수 값을 할당하거나 다른 높이 및 너비 속성과 결합할 수 있다. 이 값은 음수일 수 없다.
Top, Bottom, Baseline 화면 아래로 이동하면 값이 증가한다. 이러한 속성은 Center Y, Top, BottomBaseline 속성과만 결합 할 수 있다.
Leading, Trailing 후행(Trailing) 가장자리로 이동하면 값이 증가한다. 왼쪽에서 오른쪽 레이아웃 방향의 경우 오른쪽으로 이동하면 값이 증가한다. 오른쪽에서 왼쪽 레이아웃 방향의 경우 왼쪽으로 이동하면 값이 증가한다. 이러한 속성은 Left, RightCenter X 속성과 만 결합 할 수 있다.
Left, Right 오른쪽으로 이동하면 값이 증가한다. LeftRight 속성을 사용하지 마시오. 대신 LeadingTrailing을 사용하십시오. 이렇게하면 레이아웃이 뷰의 읽기 방향에 맞게 조정된다. 기본적으로 읽기 방향은 사용자가 설정한 현재 언어에 따라 결정된다. 그러나 필요한 경우 이를 재정의 할 수 있다. iOS에서 제약 조건 (제약 조건의 영향을받는 모든 뷰의 가장 가까운 공통 조상)을 보유한 뷰에서 semanticContentAttribute 속성을 설정하여 왼쪽에서 오른쪽과 오른쪽에서 왼쪽으로 전환 할 때 콘텐츠의 레이아웃을 뒤집을 지 여부를 지정한다.
Center X, Center Y 해석은 방정식의 다른 속성을 기반으로 한다. Center XCenter X, Leading, Trailing, RightLeft 속성과 결합 될 수 있다. Center YCenter Y, Top, BottomBaseline 속성과 결합 될 수 있다.