[TIL] Autolayout 동작 방식 이해

박주하·2025년 6월 12일

Frame-Based Layout


let label = UILabel()
label.frame = CGRect(x: 20, y: 100, width: 200, height: 40)
  • Autolayout 등장 이전 UI 배치 방식
  • frame 설정을 통해 직접 x, y 위치와 width, height를 지정해서 뷰를 배치하는 방법
  • 단순하고 계산이 직접적이라 예측 가능
  • 기기 크기나 회전에 유연 ❌

📌 frame vs bounds

Superview (부모)
+-----------------------------+
|                             |
|     +-----------------+     |
|     |  Subview        |     |
|     |  frame: (50,100)|     |
|     |  bounds: (0,0)  |     |
|     +-----------------+     |
|                             |
+-----------------------------+
개념의미기준영향
frame부모 기준 뷰의 위치와 크기부모 뷰위치 이동/크기 조절
bounds자기 내부 기준 크기와 좌표계자기 자신내부 콘텐츠 위치/스케일

Autolayout


label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    label.topAnchor.constraint(equalTo: view.topAnchor, constant: 100),
    label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
    label.widthAnchor.constraint(equalToConstant: 200),
    label.heightAnchor.constraint(equalToConstant: 40)
])
  • 뷰 사이의 제약조건(Constraints)을 사용해서 자동으로 위치와 크기를 계산하는 방식
  • 다양한 화면 크기 대응에 유리하며, 동적 UI 구성에 최적
  • 회전, 다크모드, 다국어 대응도 쉬움

💡 다양한 Attributes

  • leading, trailing, left, right, top, bottom, centerX, centerY, center, width, height...
  • leading: 왼쪽 ❌, Text가 시작되는 시점
  • trailing: 오른쪽 ❌, Text가 끝나는 시점
  • 🚨 대부분의 언어에서는 문제 없지만, 아랍권은 글을 쓰는 방향이 반대

📌 Frame vs Auto Layout

항목Frame-Based LayoutAuto Layout
코드 작성단순복잡
유연성낮음높음
회전 대응❌ 수동 계산✅ 자동 대응
화면 크기 대응❌ 불편✅ 유연
추천 상황고정된 간단 UI반응형 UI, 여러 디바이스

Autolayout의 중요 키워드


1. translatesAutoresizingMaskIntoConstraints

myView.translatesAutoresizingMaskIntoConstraints = false
  • Frame 기반 → Auto Layout 기반으로 전환할 때 꼭 설정하는 속성
  • “더 이상 Frame(AutoresizingMask) 사용 안 하고, Auto Layout으로 뷰의 위치와 크기를 계산할 거야!”
  • translatesAutoresizingMaskIntoConstraints = true일 경우, Autolayout을 결정짓기 위해 설정한 Constraints가 AutoresizingMask와 충돌하기 때문에 동작하지 않음

2. Safe Area

  • iOS 앱에서 상단 상태표시줄, 네비게이션바, 하단 탭바, 하단 Status Bar를 제외한 화면에 보여지는 안전한 영역
  • iPhone X 이후에는 화면 끝에 노치, 홈바, 카메라 홀 등이 있음
  • 이 영역을 피해서 UI를 배치하려면 Safe Area 기준으로 잡아야 함

3. IntrinsicContentSize

  • 뷰가 자기 콘텐츠만큼 필요한 크기를 스스로 계산해주는 값
  • UILabel, UIButton, UIImageView 등은 내부 콘텐츠 크기에 따라 자동 크기 결정 가능
  • Auto Layout이 크기를 지정하지 않아도, 기본적으로 사용할 수 있는 사이즈 힌트로 사용함
  • “나, 내 콘텐츠 이 정도 크기 필요해요!”라고 뷰가 Auto Layout에게 말하는 것

    🚨 예외
    UIView, UIImageView(frame 기반) 등은 intrinsic size 없음 → 반드시 constraint로 크기를 설정해야 함


📌 정리

키워드역할핵심 포인트
translatesAutoresizingMaskIntoConstraintsFrame → Auto Layout 전환반드시 false로 설정해야 충돌 방지
safeAreaLayoutGuide노치/홈바 피해서 UI 배치iPhone X 이상에서 안정적인 UI 구현
intrinsicContentSize콘텐츠 기반 자동 크기 계산UILabel/UIButton 등에 적용됨

Priority


Auto Layout은 제약 조건이 너무 많거나, 너무 적거나, 모호하면 충돌(conflict)이 발생한다. 그래서 Auto Layout은 “어떤 조건을 더 중요하게 생각할지(우선순위)”를 기준으로 가장 적절한 해결안을 스스로 찾아내려고 한다.

💡 우선순위(priority) 숫자

  • 숫자가 클수록 더 중요!
  • 무조건 지켜야 하는 조건
    • .required: 1000
  • 가능한 지키되, 필요하면 깨질 수 있는 조건
    • .defaultHight: 750
    • .defaultLow: 250
    • .fittingSizeLevel: 50

1. Content Hugging Priority

label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
  • View가 고유 크기보다 더 커지는 것을 방지하기 위한 우선순위
  • Hugging = “꽉 안고 싶어함”
  • 우선순위 높을수록 크게 퍼지는 걸 싫어함

2. Compression Resistance Priority

label.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
  • View가 고유 크기보다 작이지는 것을 방지하기 위한 우선순위
  • Resistance = “눌림 저항”
  • 우선순위 높을수록 눌리는 걸 싫어함

3. 예제 코드

  • label1, label2를 수평으로 배치
  • 레이블 간 너비 충돌 발생
  • Hugging / Compression Resistance 우선순위를 다르게 줘서
    어떤 레이블이 눌리는지 확인!
import UIKit

class ViewController: UIViewController {

    let label1 = UILabel()
    let label2 = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .white

        // 기본 설정
        label1.text = "첫 번째 레이블"
        label2.text = "두 번째 레이블이 더 길어요!"
        label1.backgroundColor = .systemYellow
        label2.backgroundColor = .systemGreen
        label1.numberOfLines = 1
        label2.numberOfLines = 1

        // 오토레이아웃 활성화
        label1.translatesAutoresizingMaskIntoConstraints = false
        label2.translatesAutoresizingMaskIntoConstraints = false

        // 뷰에 추가
        view.addSubview(label1)
        view.addSubview(label2)

        // Auto Layout Constraints
        NSLayoutConstraint.activate([
            label1.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            label2.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            label1.trailingAnchor.constraint(equalTo: label2.leadingAnchor, constant: -10),
            label1.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 100),
            label2.topAnchor.constraint(equalTo: label1.topAnchor),
        ])

        // Content Hugging & Compression Resistance 설정
        label1.setContentHuggingPriority(.defaultLow, for: .horizontal)
        label2.setContentHuggingPriority(.defaultHigh, for: .horizontal)

        label1.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        label2.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
    }
}
  • label1은 Hugging / Compression Resistance이 약해서 → 눌림
  • label2는 Hugging / Compression Resistance이 강해서 → 모양 유지
  • 즉, label1이 크기를 양보하고 줄어드는 걸 확인할 수 있다!

📌 정리

개념설명값이 클수록
Priorityconstraint 우선순위꼭 지켜야 함
Hugging Priority넓게 퍼지는 걸 방지("나 더 커지기 싫어!")더 작게 유지하려 함
Compression Resistance작아지는 걸 방지("나 눌리기 싫어!")더 크게 유지하려 함

0개의 댓글