아직은 자세히 모르는 오토레이아웃에 관해 작성해보려고 한다.
오토레이아웃은 뷰에 부과된 제약 조건에 따라 뷰 계층 구조의 모든 뷰의 크기와 위치를 동적으로 계산 해주는 친구이다.
뷰 계층의 레이 아웃은, 일련의 1차 방정식이다. 각 제약은 단일 방정식을 나타낸다.
레이아웃 가이드 : 자동 레이아웃과 상호 작용할 수 있는 직사각형 영역
대부분의 제약 조건은 사용자 인터페이스의 두 항목 간의 관계를 정의 합니다.
일반적으로 제약 조건은 각 뷰의 위치와 크기를 모두 정의해야 합니다.
다음 3가지 레이아웃은 모두 명확하고 만족스러운 레이아웃을 생성합니다.
이는 상위 뷰의 왼쪽 에지를 기준으로 뷰의 왼쪽 에지를 제한합니다. 또한 뷰에게 고정 너비를 제공합니다. 그렇게 함으로써, 오른쪽 에지의 위치는 슈퍼뷰의 크기와 기타 제약 조건을 기반으로 계산이 가능합니다.
이는 상위 뷰의 왼쪽 에지를 기준으로 뷰의 왼쪽 에지를 제한하고, 오른쪽 에지에도 같이 제한을 주었다. 그런 다음 뷰의 너비는 상위 뷰의 크기와 기타 제약조건을 바탕으로 계산이 가능하다.
이는 상위 뷰의 왼쪽 에지와 뷰의 왼쪽 에지를 제한하고, 뷰와 상위 뷰를 가운데 정렬한다. 너비와 오른쪽 에지의 위치는 모두 슈퍼뷰의 크기와 다른 조건을 기반으로 계산이 가능하다.
첫 번째의 경우, 뷰의 너비가 변경되지 않는다. 원칙적으로, 뷰에 일정한 크기를 할당 하는 것은 피해야 한다. 뷰에 고정크기를 줄 때 마다, 오토레이아웃의 능력을 감소 시키기 때문이다.
두번째, 세번째 레이아웃은 동일한 동작을 수행한다.
슈퍼뷰의 너비가 변경되어도, 뷰의 너비를 계산이 가능하고, 일정한 간격을 유지한다. 두번째의 경우가 이해하기 쉽지만, 보통 세번쨰의 경우가 더 유용한 경우가 많다. 특히 여러 항목을 가운데 정렬시에 더 유용하다.
위와 같은 뷰를 만드려고 할 때, 2가지 접근 방식이 존재한다.
// 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.widh = 1.0 * Blue.width + 0.0
위와 같은 방식이 하나 있고, 아래와 같은 방식이 존재한다.
// 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
위 두가지 방식 다 만족스럽게 동작을 한다. 장단점으로는,
1번 방식의 경우 View가 삭제 될 때 더 강력하다. Red
가 사라져도 Blue
에는 3가지 제약 조건이 남아있으므로, 한가지 제약만 추가하면 유효한 레이아웃이 생성된다.
하지만 2번 방식의 경우는 뷰가 삭제시 제약 조건이 한가지만 남는다.
반면에, 1번에서 View
의 위 아래 정렬시에는 위쪽 및 아래 쪽 제약조건이 동일한 상수 값을 사용하는지 확인해야하고, 하나의 상수를 변경시에 다른 상수도 변경해야 한다.
지금까지 예제에는 제약 조건을 사용하여 모든 뷰의 위치와 크기를 정의했지만, 일부 뷰는 현재 콘텐츠에 따라 자연스러운 크기를 가집니다. 이를 고유 콘텐츠 크기라고 합니다.
위의 Red, Blue
예제를 pink, purple
로 해서 만들어 보았다. 최종 결과는 위의 Red, Blue
의 예제와 동일하다.
private var pinkView: UIView = UIView()
private var purpleView: UIView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
pinkView.backgroundColor = .systemPink
purpleView.backgroundColor = .purple
// 먼저 addSubView로 뷰를 추가해주어야한다.
self.view.addSubview(pinkView)
self.view.addSubview(purpleView)
// 이 과정 필수 ! false는 AutoLayout을 따르겠다는 의미 !
pinkView.translatesAutoresizingMaskIntoConstraints = false
purpleView.translatesAutoresizingMaskIntoConstraints = false
/// Vertical Constraint
pinkView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0).isActive = true
purpleView.leadingAnchor.constraint(equalTo: pinkView.trailingAnchor, constant: 15.0).isActive = true
view.trailingAnchor.constraint(equalTo: purpleView.trailingAnchor, constant: 20.0).isActive = true
pinkView.widthAnchor.constraint(equalTo: purpleView.widthAnchor).isActive = true
/// Horizontal Constraint
pinkView.topAnchor.constraint(equalTo: view.topAnchor, constant: 50.0).isActive = true
purpleView.topAnchor.constraint(equalTo: view.topAnchor, constant: 50.0).isActive = true
view.bottomAnchor.constraint(equalTo: pinkView.bottomAnchor, constant: 50.0).isActive = true
view.bottomAnchor.constraint(equalTo: purpleView.bottomAnchor, constant: 50.0).isActive = true
}
아래의 코드 처럼 작성을 하면 .isActive = true
작성하지 않아도 된다.
NSLayoutConstraint.activate([
pinkView.topAnchor.constraint(equalTo: view.topAnchor, constant: 50.0),
purpleView.topAnchor.constraint(equalTo: view.topAnchor, constant: 50.0),
view.bottomAnchor.constraint(equalTo: pinkView.bottomAnchor, constant: 50.0),
view.bottomAnchor.constraint(equalTo: purpleView.bottomAnchor, constant: 50.0)
])
안전영역에 붙이려면 아래와 같이 작성을 해주면 된다.
Button.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 20).isActive = true
Button.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 20).isActive = true
오토레이아웃에 대해서 아직 다루지 않은 부분이 더 있을거라고 생각하지만, 차후에 더 작성해보도록 하겠다. 스냅킷이나 컨텐츠 허깅등 여러가지,,,
참조