이 글은 애플의 Auto Layout공식 문서를 기반으로 작성되었습니다!
개요
AutoLayout이 필요한 이유
각기 다른 화면 크기
기본적으로, 화면에 무언가를 그린다는 것은 특정 위치의 픽셀에게 어떤 색상을 보여달라고 요청을 하는 것이다.
그 픽셀들, 점들이 모여서 선을 이루고, 그 선들이 면을 이루면서 우리가 보는 UI가 그려지게 된다.
그런데 그 UI를 그리는 화면의 크기가 항상 같지 않다.
세상에는 엄청나게 많은 종류의 기기들이 존재하고, 그에 따라 수 많은 종류의 화면 크기들이 존재한다.
아이폰도 그 크기가 항상 같지 않다.
처음에는 3.5인치의 화면 크기였고, 그 다음에는 4인치, 그 다음에는 4.7인치… 최근에는 6.1인치까지 그 화면크기가 커졌다.
다른 기기지만 보여주는 건 같아야 해
문제는 다른 화면 크기를 가지고 있어도, 아이폰이라면, 그리고 같은 어플을 깔았다면 보여주는 내용물은 같아야 한다.
사실 꼭 완전히 똑같을 필요는 없지만, 내용물의 위치나 화면 대응 방식은 똑같아야한다는 것이다.
아래의 UI를 화면에 그린다고 해보자. ▼
var square1 : UIView {
let square = CGRect(x: 20, y: 100, width: 157.5, height: 157.5)
let uiView = UIView(frame: square)
uiView.backgroundColor = .cyan
return uiView
}
var square2 : UIView {
let square = CGRect(x: 197.5, y: 100, width: 157.5, height: 157.5)
let uiView = UIView(frame: square)
uiView.backgroundColor = .orange
return uiView
}
왼쪽과 오른쪽 그리고 가운데에 20px의 패딩을 넣고, 나머지 공간은 한 변이 157.5px인 정사각형 두 개를 넣었다.
그 중 하나는 하늘색, 다른 하나는 오렌지색으로 채웠다.
이 UI는 아이폰 se3(아이폰 8과 동일)에 맞춰진 UI로 아이폰 se3에서 보면 좌우 비율이 잘 맞지만,
그런데 이를 아이폰 14 pro에서 보게되면 모습이 조금 이상하다. ▼
같은 UI지만, 화면을 그리는 환경에 따라 보여지는 모습이 다르게 된다.
왜 이런 현상이 일어나는 것일까?
이런 현상이 일어나는 이유는 간단하다.
위에서 UI를 화면에 그리는 방식은 최상단의 뷰에 우리가 제공하는 UI요소인 frame을 그리는 것이다.
원래 뷰가 자신을 화면에 배치하기 위해 명시적인 위치와 크기인 frame을 설정하여 상위 뷰에 컨텍스트를 제공하면,
상위 뷰는 이 컨텍스트를 활용하여 자신의 좌표계에 따라 정확히 어디에 어떤 크기로 표시해야 하는지 시스템에게 알려주어 화면에 표시한다. ▼
그런데 이를 절대 위치로 전달하게 되면서 문제가 발생한다.
엄밀히 따지자면, 위의 UI는 아이폰 se3의 화면 크기 값을 상수로 사용하여 디자인했기에 아이폰 se3의 좌표계에서만 제대로 동작하는 것이다. ▼
절대 위치로 전달을 하게 되면 좌표계에 따라 보여지는 비율이 달라지게 된다.
너비와 높이가 100인 사각형을 x와 y 각각 50인 좌표에 그린다고 했을 때, 세로로 긴 좌표계와 가로로 긴 좌표계에서 보여주는 모습은 같아도 비율은 달라지게 된다. ▼
조금 와닿게 비유하자면, 절대 위치로 전달하는 것은 한 사이즈의 옷을 여러 체형의 사람에게 입히는 것과 같다. ▼
그럼 어떻게 해결할까?
이런 현상이 iOS에서만, 아이폰에서만 일어나는 것이 아니기에 각자의 환경에서 이를 해결하고자 하는 방법론은 굉장히 많았다.
하나의 사이즈의 옷이 아니라, 각 환경에 맞게 옷의 사이즈가 변하게 할 수 있는 그런 방법론들이 많이 등장했다.
CSS에 있는 Flexbox, Grid 그리고 Constraint 기반의 방법론이 있었고, 그 중에서 Auto Layout은 Constraint 방법론에 해당한다.
위의 문제점은 이전부터 많은 사람들이 고민한 내용이고, 그 해결방안들이 하나의 템플릿, 즉 방법론들로 만들어졌다.
Auto Layout도 그 중 하나의 방법론이고, 애플의 기기들에서 이런 문제들을 효과적으로 해결할 수 있다.
그렇다면 Auto Layout은 뭔데?
Auto Layout의 등장과 현재
Auto Layout은 iOS 6에서 처음 소개되었으며, UI 요소의 레이아웃에 대한 사고 방식에 큰 영향을 줬다.
그러나 초기에는 사용하기 편하거나 깔끔하지 않은 API로 크게 주목받지 못했다.
이후에 auto layout과 관련된 여러 라이브러리들이 업데이트 되면서 사용성과 효율성이 크게 향상되어 현재의 auto layout이 된 것이다.
간단히 말하자면 Auto Layout은…
Auto Layout은 앞에서도 언급했지만, Constraint 기반의 동적 레이아웃 구축 방법론이다.
Constraint, 제약 조건을 두어 UI 컴포넌트들을 동적으로 배치할 수 있는 방법론이라고 할 수 있다.
Auto Layout은 뷰 간의 관계를 나타내기 위해 제약 조건을 사용함으로써 이러한 프레임(화면)을 자동으로 생성한다.
Auto Layout은 제약 조건을 설정한 한 결과에 문제가 없다면, 크기와 위치를 계산하여 제공한다.
간단히 말하자면 Auto Layout이란, 제약 조건(Constraints)에 따라 뷰 계층 구조에 있는 모든 뷰의 크기와 위치를 동적으로 지정하는 것이다.
이제 Auto Layout에 대해 넓게 이해가 됐을 것이라고 생각된다.
위의 내용만 봐서는 넓고 얕게 이해만 했을 것이기에 '그래서 Auto Layout이 정확히 뭐고 어떻게 사용하는거지?' 라는 의문이 남을 것이라고 생각된다.
이제부터는 그런 남은 의문점들을 해결하기 위해 좀 더 깊게 알아보자.
Auto Layout
Auto Layout은 제약 조건을 통해 뷰 계층 구조 내의 모든 뷰의 크기와 위치를 동적으로 계산한다.
예를 들어, 버튼을 사진 아래에 배치한다고 해보자.
이 때, 버튼의 상단 가장자리 부분이 사진의 하단 가장자리 부분과 8px의 거리를 두게 제약을 설정했다고 해보자. ▼
이렇게 되면 사진의 위치나 크기가 변하면 버튼의 위치도 자동으로 재조정 된다. ▼
즉, 상대적인 위치를 설정하여 인터페이스를 동적으로 만들 수 있게 된다.
이러한 제약 기반의 설계 방식을 사용하면 내부 및 외부 변경에 동적으로 대응할 수 있는 사용자 인터페이스를 구축할 수 있다.
외부 변경
외부 변경은 상위 뷰의 크기나 모양이 변경되었을 때 발생한다.
각 변경에 따라 뷰 계층의 레이아웃을 업데이트하여 사용 가능한 공간을 최대한 활용해야 한다.
다음은 일반적인 외부 변경의 예이다.
- 사용자가 창 크기를 조정. (OS X)
- iPad에서 Split View에 진입하거나 나가기. (iOS)
- 기기의 방향 변경. (iOS)
- 활성 통화 및 오디오 녹음 바가 표시되거나 사라짐. (iOS)
- 다양한 사이즈 클래스를 지원.
- 다양한 화면 크기를 지원.
이러한 변경 대부분은 런타임에서 발생할 수 있으며 앱에서 동적으로 대응해야 한다.
"그렇다면 창 크기를 조절할 일도 없고, 방향 변경도 막아놓은 아이폰 앱의 경우에는 이렇게 할 필요가 없지 않나요?"
런타임에서 화면의 크기나 비율이 변경되지 않더라도, 적응형 인터페이스를 적용해놓으면 여러 종류의 아이폰에서 모두 동일하게 잘 작동하는 앱을 만들 수 있다.
내부 변경
내부 변경은 사용자 인터페이스의 뷰나 컨트롤의 크기가 변경되었을 때 발생한다.
다음은 내부 변경의 일반적인 원인이다.
- 앱에서 표시되는 컨텐츠 변경.
- 앱이 여러 나라를 지원.
- 앱이 동적 글꼴 크기 조정을 지원. (iOS)
앱에서 표시되는 컨텐츠 변경
앱에서 보여주는 컨텐츠가 변경되면, 새롭게 보여주고자 하는 컨텐츠가 이전과는 다른 레이아웃을 필요로 할 때가 있다.
텍스트나 사진을 보여줄 때 이런 상황이 많이 일어나기에 거의 대부분의 앱에서 이에 대한 대비가 필요하다. ▼
앱에서 언어가 바뀔 때
또한 앱이 다른 언어를 지원하게 될 때도 생각해야한다.
예를 들어, 영어를 기본적으로 지원하는 앱에서 독일어와 일본어를 지원한다고 해보자.
독일어는 평균 단어 길이가 영어보다 길다.
긴 합성어도 많이 존재하고, 상대적으로 복잡한 문법 규칙으로 인해 문장의 길이가 길어지는 경우가 있다.
이런 특성으로 인해 영어에서 독일어로 언어를 바꾸게 되면, 조금 더 많은 공간을 차지해야할 수 있다.
반대로 일본어는 분절문자인 알파벳과 다르게 음절문자이기 때문에 하나의 표기로 자음과 모음을 동시에 나타낼 수 있어 평균적으로 단어 길이가 짧은 편이다.
그 외에도 주어와 목적어 등과 같이 문장 구성 요소를 확실하게 나타내지 않아도 의미 전달이 되기에 영어에 비해 상대적으로 적은 텍스트 공간을 사용한다.
날짜와 숫자에 대한 형식
날짜를 표기하는 방법도 문제가 될 수 있다.
한국의 경우 yyyy/mm/dd 의 형식을 택하고 있지만, 미국의 경우엔 mm/dd/yyyy 의 형식을 사용한다.
"어차피 길이는 다 똑같지 않나?"
표기 방식에 쉼표가 들어가거나 다른 표기 문구가 들어감으로써 약간의 공간 차이가 생길 수 있다.
아주 작은 변화지만 이런 작은 변화에도 대응할 수 있어야 한다. ▼
(아래의 예시는 이 미미한 차이를 조금 극단적으로 보여주기 위해 언어도 변경했다.)
언어에 따른 레이아웃 구성
한국어와 영어, 그리고 대부분의 언어들은 왼쪽에서 오른쪽으로 읽는 레이아웃을 사용한다.
하지만 아랍어와 히브리어는 오른쪽에서 왼쪽으로 읽는 레이아웃을 사용한다. ▼
"언어만 오른쪽 정렬로 바꿔주면 되는거 아닌가?"
일반적으로 사용자 인터페이스 요소의 순서도 레이아웃의 방향과 일치해야한다.
아랍어의 경우에는 언어에 맞추어 레이아웃도 오른쪽에서 왼쪽으로 바뀌었기 때문에, 언어가 한국어일 때 오른쪽 아래에 있던 버튼은 아랍어일 때는 왼쪽 아래로 가야한다.
동적 글꼴 크기 조정
iOS 앱이 동적 글꼴 크기 조정을 지원하는 경우 사용자는 앱에서 사용되는 글꼴 크기를 변경할 수 있다.
이는 사용자 인터페이스의 텍스트 요소의 높이와 너비를 모두 변경할 수 있다.
사용자가 앱을 실행하는 동안 글꼴 크기를 변경하면 글꼴과 레이아웃 모두가 적응해야 한다. ▼
Auto Layout과 프레임 기반 레이아웃 비교
사용자 인터페이스를 배치하는 데는 세 가지 주요 접근 방식이 있다.
프로그래밍을 통해 UI를 배치할 수 있고, autoresizing mask를 사용하여 외부 변경에 대한 일부 응답을 자동화할 수도 있으며, Auto Layout을 사용할 수도 있다.
전통적으로 앱은 뷰 계층 구조의 각 뷰에 대해 프로그래밍적으로 프레임을 설정하여 사용자 인터페이스를 배치했다.
프레임은 뷰의 원점, 높이 및 너비를 상위 뷰의 좌표계에서 정의했다.
프로그래밍을 통한 UI 배치
UI를 배치하려면 뷰 계층의 모든 뷰에 대해 크기와 위치를 계산해야 했다.
그런 다음 변경이 발생하면 영향을 받는 모든 뷰에 대해 프레임을 다시 계산해야 했다. ▼
프레임을 프로그래밍적으로 정의하는 것은 가장 강력한 유연성을 제공한다.
변경이 발생하면 원하는 변경을 원하는 대로 수행할 수 있다.
그러나 모든 변경을 직접 관리해야 하므로 간단한 사용자 인터페이스를 배치하는 데에도 설계, 디버그 및 유지 관리하는 데 상당한 노력이 필요하다. ▼
실제로 적응형 UI를 만드는 것은 난이도를 몇 배로 증가시킨다.
Autoresizing mask
일부 노력을 줄이기 위해 autoresizing mask를 사용할 수 있다.
Autoresizing mask는 개발자가 동적 레이아웃을 쉽게 구현할 수 있도록 애플이 이전에 도입했던 방법으로, 뷰의 프레임이 상위 뷰의 프레임 변경시 어떻게 변경되는지 정의한다.
조금 쉽게 설명을 하자면, Autoresizing mask는 상위 뷰의 크기와 위치 변경에 따라 하위 뷰(프레임)의 크기와 위치를 재정의 하는 것이다.
프로그래밍을 통한 UI배치보다 훨씬 나은 모습을 보여주지만, autoresizing mask에는 몇가지 단점이 존재한다.
- 제한된 유연성
Autoresizing mask는 단순히 뷰의 크기와 위치를 기반으로 한 자동 조정만을 다룬다.
따라서 복잡한 UI 레이아웃을 구현하기에는 제한적일 수 있고, 또한 뷰 간의 복잡한 제약 관계를 표현하기에는 제한적일 수 있다. - 제약 충돌 가능성
Autoresizing mask를 사용하면 뷰 크기의 자동 조정에 대한 제약 충돌이 발생할 수 있다.
예를 들어, autoresizing mask를 사용하여 뷰의 너비와 높이를 자동으로 조정하려고 할 때, 다른 제약 조건과 충돌하여 의도한대로 동작하지 않을 수 있다. - 유지 보수의 어려움
Autoresizing mask는 코드에서 뷰의 자동 크기 조정을 수행하므로, 레이아웃 변경이 필요한 경우 코드의 수정이 필요하다.
이는 유지 보수가 어려울 수 있으며, 레이아웃 변경에 따른 예기치 않은 부작용을 발생시킬 수도 있다.
Auto Layout
Auto Layout은 전혀 새로운 패러다임을 나타낸다.
뷰의 프레임에 대해 생각하는 대신, 뷰 간의 관계에 대해 생각한다.
절대적인 수치보다 상대적인 위치에 대해 생각을 한다는 의미와 같다.
Auto Layout은 일련의 제약 조건(Constraint)을 사용하여 UI를 정의한다.
제약 조건은 일반적으로 두 개의 뷰 간의 관계를 나타낸다.
그런 다음 Auto Layout은 이러한 제약 조건을 기반으로 각 뷰의 크기와 위치를 계산한다.
이렇게 하면 내부 및 외부 변경에 동적으로 대응하는 레이아웃이 생성된다.
특정 동작을 만들기 위해 제약 조건 집합을 설계하는 논리는 절차적 또는 객체 지향 코드를 작성하는 논리와 매우 다르다.
다행히도 Auto Layout을 마스터하는 것은 다른 프로그래밍 작업을 마스터하는 것과 다를 바 없다.
두 가지 기본 단계만 거치면 된다.
첫번째는 제약 조건 기반 레이아웃의 논리를 이해하는 것이고, 두번째는 API를 배우는 것이다.
다른 프로그래밍 작업을 배울 때와 마찬가지로 이러한 단계를 성공적으로 수행했을 때 Auto Layout을 마스터한 것과 같다고 할 수 있다.
마치며
Auto Layout이라는 단어가 요즘에는 피그마에서도 사용되면서 엄청 생소한 단어는 아니지만, 처음에 Auto Layout을 접했을 때는 너무나도 생소한 단어였다.
개념도 확실히 이해되지 않고, 제약조건을 두어 UI를 설계한다는 것 그 자체가 굉장히 이해하기 어려웠다.
제약조건이라는 단어는 무언가를 제한한다는 의미를 내포하고 있는데, 어떻게 제한을 통해 다양성을 추구하는지 이해가 잘 안됐다.
그런 부족한 이해들을 이번에 공식문서와 다른 글들을 통해 학습하고 정리하는 과정을 가지면서 메꾸게 되었다.
왜 Auto Layout이 필요한지, 다른 레이아웃들보다 좋은 점, 그리고 제약조건이 말하고자 하는 것을 확실히 이해할 수 있게 되었다.
이제는 Auto Layout 사용에 대해 익히면서 하나씩 구현을 해볼 차례인거 같다.
다들 화이팅이다~
'Develop > iOS' 카테고리의 다른 글
[iOS][Swift] 클로져 캡쳐에 대한 이해 (0) | 2024.02.11 |
---|---|
[iOS][Swift] Two Phase Initialization (0) | 2024.02.09 |
[iOS][Swift] Swift의 메모리 관리 : ARC 1 (0) | 2024.02.09 |
[iOS][Swift] MetaType이란 (0) | 2024.01.23 |
[iOS] Delegate 패턴 (0) | 2024.01.23 |