티스토리 뷰

[iOS 오토레이아웃 ] 제약조건구조 ( Anatomy of a Constraint )

from Auto layout Guide - Getting Started - Auto Layout Without Constraints




제약조건은 하나의 식입니다. 대부분의 제약조건은 두 개의 뷰의 관계를 나타냅니다. 뷰는 layout guide나 safe area 등도 될 수 있습니다. 또한 하나의 뷰의 서로다른 속성에도 제약조건을 걸 수 있습니다. 같은 성격일 때만요. 예를 들면 view의 width height ratio가 있습니다. 또한 height나 width에 강제로 값을 줄 수 도 있는데 이 때는 seconditem은 없고 second attribute는 'nt an attribute'로 나타내고 multiplier는 0입니다.


Auto Layout Attributes

오토레아웃 속성은 다음과 같습니다. baseline속성 같은 경우에는 text를 포함하는 뷰에는 first, last로 나뉘어 져 있습니다.


Sample Equations

속성은 크게 2가지로 나뉩니다. size와 location으로 나뉘는데 szie속성 location간의 관계를 맺을 수 없고, 위치 속성에 상수값이나 유효하지 않은 값을 넣을 수 없습니다. (1.0이상의 수) 수직과 수평간의 관계도 맺을 수 없고 leading&trailing과 left right관계도 맺을 수 없습니다. 

예를들어 view top에 20을 주는 것은 추가적인 정보 없이는 의미가 없습니다. 다른 view와의 관계가 반드시 필요합니다. safe area  top에서 20만큼 아래로 떨어지게끔 한다던지 해야 합니다. 그러나 height에 20을 주는 것은 괜찮습니다. 


  1. // Setting a constant height
  2. View.height = 0.0 * NotAnAttribute + 40.0
  3. // Setting a fixed distance between two buttons
  4. Button_2.leading = 1.0 * Button_1.trailing + 8.0
  5. // Aligning the leading edge of two buttons
  6. Button_1.leading = 1.0 * Button_2.leading + 0.0
  7. // Give two buttons the same width
  8. Button_1.width = 1.0 * Button_2.width + 0.0
  9. // Center a view in its superview
  10. View.centerX = 1.0 * Superview.centerX + 0.0
  11. View.centerY = 1.0 * Superview.centerY + 0.0
  12. // Give a view a constant aspect ratio
  13. View.height = 2.0 * View.width + 0.0

Equality, Not Assignment

변수가 값을 저장하는 것처럼 할당하는 게 아니라 하나의 식입니다. 따라서 역도 성립합니다.
위 예제와 차이를 느껴봅니다. 
  1. // Setting a fixed distance between two buttons
  2. Button_1.trailing = 1.0 * Button_2.leading - 8.0
  3. // Aligning the leading edge of two buttons
  4. Button_2.leading = 1.0 * Button_1.leading + 0.0
  5. // Give two buttons the same width
  6. Button_2.width = 1.0 * Button.width + 0.0
  7. // Center a view in its superview
  8. Superview.centerX = 1.0 * View.centerX + 0.0
  9. Superview.centerY = 1.0 * View.centerY + 0.0
  10. // Give a view a constant aspect ratio
  11. View.width = 0.5 * View.height + 0.0

변수가 값을 저장하는 것처럼 할당하는 게 아니라 하나의 식입니다. 따라서 역도 성립합니다.
이렇게 다양한 방법이 있는데 어느게 맞다 틀리다 보다는 일관성있게 작성하는게 정신건강에 좋습니다.

이 예제에서는 다음과 같은 가이드를 따릅니다.
1. multiplier는 소수보다는 정수
2. constant는 음수보다는 양수
3. 가능한 경우 뷰는 레이아웃 순서대로 나타나야합니다 leading에서 trailing, top 에서 bottom으로 ...?


Creating Nonambiguous, Satisfiable Layouts

제약조건을 만들 때는 명확해야하는데 그렇지 않은 경우가 있습니다. 그럴 때는 크게 ambiguous나 unsatisfiable가지로 나뉩니다. ambiguous는 다양한 해결방법이 있을 수 있지만 unsatisfiable는 없습니다.
일반적으로 제약조건은 뷰의 size와 위치를 지정해야 합니다. 아래 그림을 보겠습니다.



첫번째는 leading과 width를 주었습니다. trailing은 superview의 사이즈나 다른 제약조건에 의해 자동으로 계산됩니다.

두번째는 leading과 trailing을 주었습니다. width는 자동으로 계산됩니다.

세번째는 leading과 center 정렬을 주었습니다. width와 trailing역시 자동으로 계산됩니다.

각 레이아웃은 하나의 뷰와 두 개의 수평 제약조건을 가지고 있습니다. 다 다르지만 정상적으로 작동합니다. 각각을 자세히 살펴보겠습니다.

첫 번째 뷰의 width는 고정이라서 변하지 않습니다. autolayout 관점에서는 별로 좋지 못합니다. 왠만하면 고정값을 width와 height에 주지 않는 게 좋습니다. 

두 번째와 세번째는 같습니다. 똑같이 고정된 margin을 유지 할 겁니다. 하지만 두 번째뷰는 이해하기 좀 더 쉽습니다. 그러나 세번 째 뷰는 여러 뷰를 가운데 정렬할 때 유용합니다. 항상 최상을 생각해야 하고 일관성있게 작성해야 합니다.

다음 예는 두 개의 뷰입니다.


위 이미지처럼 가로와 세로에서 같은 넓이를  갖게 할면 어떻게 해야 할까요?


다음과 같습니다. 

// Vertical Constraints

Red.top = 1.0 * Superview.top + 20.0

Superview.bottom = 1.0 * Red.bottom + 20.0

Blue.top = 1.0 * Superview.top + 20.0

Superview.bottom = 1.0 * Blue.bottom + 20.0


// Horizontal Constraints

Red.leading = 1.0 * Superview.leading + 20.0

Blue.leading = 1.0 * Red.trailing + 8.0

Superview.trailing = 1.0 * Blue.trailing + 20.0

Red.width = 1.0 * Blue.width + 0.0


2개의 뷰에 수평&수직 제약조건 4개가 있습니다. 위 제약조건들은 절대적인 게 아닙니다. 다른 방법도 있습니다.





// Vertical Constraints

Red.top = 1.0 * Superview.top + 20.0

Superview.bottom = 1.0 * Red.bottom + 20.0

Red.top = 1.0 * Blue.top + 0.0

Red.bottom = 1.0 * Blue.bottom + 0.0


//Horizontal Constraints

Red.leading = 1.0 * Superview.leading + 20.0

Blue.leading = 1.0 * Red.trailing + 8.0

Superview.trailing = 1.0 * Blue.trailing + 20.0

Red.width = 1.0 * Blue.width + 0.0


차이를 느껴봅니다.

어떤 게 더 좋을까요? 둘 다 장단점이 있기 때문에 우열을 가리기 힘듭니다. 각각의 장단 점을 보죠.
첫번 째 예제는 뷰가 삭제 됐을 때 문제가 없습니다. 뷰를 제거하면 뷰와 관련된 제약조건이 다 없어집니다. 첫 번째 예제에서 레드뷰를 제거하면 나머지 하나는 3개의 제약조건을 가지게 됩니다. 여기서 하나만 추가하면 됩니다. 두 번째 뷰는 레드뷰를 제거하면 블루뷰는 제약조건이 하나밖에 남지 않습니다. 

반면에 top&bottom 간격을 조정하려면 첫번 째 예제는 두 개의 뷰 모두 수정해야 하지만 두 번째 뷰는 레드뷰만 수정하면 됩니다.

Constraint Inequalities

제약 조건에는 '='뿐만 아니라 '>=', '<='로도 표현할 수 있습니다. 

  • // Setting the minimum width
  • View.width >= 0.0 * NotAnAttribute + 40.0
  • // Setting the maximum width
  • View.width <= 0.0 * NotAnAttribute + 280.0


  • 하지만 이는 뷰의 측면마다 2개의 제약조건이 필요하다는 공식을 깨뜨립니다. 즉, 위 예제와 같이 제약조건을 준다면 추가적인 제약조건이 꼭 필요합니다. 안 그러면 ambiguous라고 뜰겁니다. 

    Constraint Priorites

    제약조건에는 우선순위가 있습니다. 1~1000까지 줄 수 있고 1000은 required입니다. 초기에는 required로 설정됩니다. 오토레이아웃은 우선순위에 따라 제약조건을 가지고 계산합니다. 우선순위가 낮은 제약조건은 건너 뛸 수도 있습니다. 그렇다고 이 제약조건이 없어지는 건 아닙니다. 레이아웃에 영향을 미칠 수 있습니다. 

    예를 들어 아래 와 같이 제약조건에 우선순위가 적용됐다면 blue 뷰는 레드뷰에 8이상 가까워 질 수 없습니다.
    하지만 2번 또한 blue뷰를 red뷰에 가깝게 하려고 하고 있습니다. 우선순위가 낮기 때문에 표면으로 들어나지 않을 뿐입니다.
    1. 1 Blue.leading >= 1.0 * Red.trailing + 8.0 @ 1000
    2. 2 Blue.leading <= 1.0 * Red.trailing + 8.0 @ 250

    우선순위에는 애플이 제공해주는 기본 값들이 있습니다. required 1000, high 750, low 250 fittingSizeLevel(50) 그리고 굳이 무조건 1000으로 하지 않아도 되고 다른 것들보다 높거나 낮게 해주면 됩니다. 때에따라서는 차이를 많이 줘야 할 수 도 있습니다. 

    Intrinsic Content Size

    뷰마다 내용을 표시할 수 있는 고유영역. 모든 뷰에 있는 것은 아니다.

    View

    Intrinsic content size

    UIView and NSView

    No intrinsic content size.

    Sliders

    Defines only the width (iOS).

    Defines the width, the height, or both—depending on the slider’s type (OS X).

    Labels, buttons, switches, and text fields

    Defines both the height and the width.

    Text views and image views

    Intrinsic content size can vary.

     예를들어 버튼의 intrinsic content size는 text 크기와 길이에 의해 결정되고 이미지뷰는 이미지 크기에 의해 결정된다. 텍스트뷰는 내용과 스크롤링이 되는지 안 되는지, 다른제약조건에 의해 달라진다. 에를들어 스크롤링이 되면 뷰는 intrinsic content size가 없다. 스크롤링이 안 되면 줄바꿈에 상관없이 텍스트 사이즈로 측정된다. 예를들어 텍스트에 enter가 없으면 단일 행에 필요한 높이와 너비를 계산한다. 만약 width를 주면 그에 맞게 height가 계산된다.

    Intrinsic content size와 관련되서 중요한 개념 2가지가 있다.
    Content hugging과 Content compression resistance이다. (CHCR)

    Content hugging은 최대값 같이 작용한다. 뷰가 늘어날려고 할 때 intrinsic content size를 지키려고 하는 힘이다.

    Content compression resistance는 최소값이다. 뷰가 줄어들려고 할 때 intrinsic content size를 지키려는 힘이다.

    그리고 이 둘도 우선순위를 가진다. 초기값으로 Content hugging은 250, Content Compression resistance는 750이다. 

    따라서 뷰가 늘어나기 쉽다. 

    왠만하면 intrinsic content size를 사용하려고 노력하라. content에 따라서 뷰가 동적으로 변할 수 있고 제약조건을 줄일 수 있다. 그리고 가이드

    연속된 뷰를 늘릴 때 content-hugging prioriy를 다르게 하라. 같다면 어떤 뷰를 늘릴지 오토레이아웃은 모른다. label과 text field를 예로들면 text field가 늘어나고 label은 intrinsic content size를 지키려면 text field의 horizontal content-hugging priority가 label보다 작아야 한다.

    이런 상황이 흔해서 IB에서 초기값으로 설정해준다. label의 horizontal content-hugging priority를 251로 코드롤 하려면 직접해야한다

    뷰가 원치 않게 늘어나는 이상한 현상에는 content-hugging priority를 늘려보라

    baseline은 뷰가 intrinsic content height를 유지할 때만 잘 작동한다.

    스위치 같은 뷰는 항상 intrinsic content size를 유지해야 하니 CHCR priorities를 적절히 올려라

    required CHCR를 피하라. 뷰가 잘 못된 사이즈로 나타나는 게 conflict를 만드는 것보다 좋다. 대신 999를 사용하라. 


    Intrinsic Content Size vs Fitting size

    Intrinsic content size는 auto layout의 input이고 Fitting size는 output이다 이 사이즈는 뷰의 제약조건에 의해 계산된다. 뷰가 subview를 auto layout을 이용해서 배치할 경우에 계산된다. stack view가 좋은 예이다.
    다른 제약조건 없다면, auto layout engine은 스택뷰의 속성과 자식뷰로 스택뷰 크기를 계산한다. 즉 스택뷰 자체는 intrinsic content size가 없지만 있는 것처럼 느껴진다. 그래서 스택뷰의 CHHR을 주는 것은 효과가 없다.
    stackview에 size를 주고 싶다면 제약조건을 직접 주거나 자식뷰의 제약조건을 줘야 한다.

     

    Interpreting Values


    반응형
    공지사항
    최근에 올라온 글
    최근에 달린 댓글
    Total
    Today
    Yesterday
    링크
    TAG
    more
    «   2025/02   »
    1
    2 3 4 5 6 7 8
    9 10 11 12 13 14 15
    16 17 18 19 20 21 22
    23 24 25 26 27 28
    글 보관함