UITraitCollection 공부
이전에 화면 회전과 관련된 Enumeration인 UIInterfaceOrientation
의 공식 문서를 보던 도중 iOS 8부터 UITraitCollection
을 쓰라고 되어 있어 얼핏 보았던 기억이 있다. 타고 들어간 공식 문서를 보아도 감이 잘 안 잡히고 Building Adaptive Apps with UIKit - WWDC 2014을 대충 봐도 잘 이해가 되지 않았다. 그래서 다시 한 번 정리를 해보려고 한다.
(제가 이해한 대로 써보았으니 이상한 것이 있으면 피드백 주시면 감사하겠습니다.)
UITraitCollection이란?
원래 아이폰은 단일 디바이스 크기를 지원했지만 아이패드, 애플 워치 등 새로운 기기의 등장과 아이폰 자체의 화면 크기 변화, 그리고 폰트나 로컬라이징 이슈 등 다양한 것들의 변화에 대응하여 UI를 효과적으로 다룰 도구가 필요했고 그래서 iOS 8 이후 소개된 개념이 UITraitCollection
이다.
위의 그림은 Making Apps Adaptive, Part 1 - WWDC 2016에서 나온 것으로 UITraitCollection
은 iOS의 인터페이스 환경을 나타내는 trait들의 모음이라고 할 수 있다. UI를 배치하는 Layout, 모습을 표현하는 Appearance, 그리고 3D Touch의 가능 여부까지 담고 있다. UIScreen
, UIWindow
, UIViewController
, UIPresentationController
, 그리고 UIView
은 UITraitEnvironment
프로토콜을 따르는 데 이 프로토콜은 Required인 traitCollection
프로퍼티를 가지고 있기 때문에 우리가 보통 제어하는 뷰와 뷰 컨트롤러는 traitCollection
을 기본 값으로 가지고 있다.
Size Class
그 중 중요한 Size Class를 보자.
Size Class는 UIUserInterfaceSizeClass
라는 열거형으로 표현이 되며 여기에는 unspecified
, compact
, regular
가 있다. compact
는 쉽게 말해서 콘텐츠를 표현하는 데 있어 제약이 크다는 것이다. 반면 regular
는 제약이 없어 자유롭게 표현할 수 있다고 생각하면 된다. UITraitCollection
은 인스턴스 프로퍼티로 horizontalSizeClass
, verticalSizeClass
를 가지고 있다. 그래서 나올 수 있는 Size Class의 조합은 총 4가지이다.
기기별 Size Class
아래 그림은 기기별 풀 사이즈 스크린을 보일 때 기본적인 가로, 세로 사이즈 클래스를 나타낸다.
특이한 것은 아이폰 플러스(6+, 7+, 8+) 같은 경우 가로 모드 시 가로의 사이즈 클래스가 Regular
로 나타난다는 것이다. 그래서 아이폰 플러스에서 애플이 기본으로 제공하는 메일 앱이나, 메시지 앱을 가로 모드로 보면 아이패드에서 볼 수 있는 UISplitViewController
를 볼수 있다.
traitCollectionDidChange(_:)
이렇듯 사이즈 클래스를 나누어 놓아 개발자로 하여금 기기, 오리엔테이션 등 상황에 따라 UI를 변화시켜 컨텐츠를 효과적으로 보여줄 수 있는 반응형 UI를 만들 수 있게 하였다. 이것을 만드는 데 가장 중요한 메소드가 UITraitEnvironment
프로토콜의 traitCollectionDidChange(_:)
이다. 이 메소드를 통해 개발자는 기기의 동작 환경이 바뀌었을 때적절한 UI로 재구성하는 기회를 얻는다. (UIScreen, UIWindow, UIViewController, UIPresentationController, 그리고 UIView가 UITraitEnvironment 프로토콜을 따른다.)
traitCollection
은 screen
에서부터 값을 가진다. 값을 가진다는 의미는 기기의 방향, 기기 종류, 외향 등 모든 trait이 값을 가진다는 뜻이다. 이렇게 구성된 traitCollection
은 screen
에서 window
로, window
에서 root viewController
로, 그 다음 view
, subview
… 순으로 전파가 된다. 이렇게 아래로 전파가 될 때마다 traitCollectionDidChange(_:)
메소드가 불리게 된다.
그림과 같이 만약 UI를 traitCollection
의 변경에 따라 바꾸고 싶다면 아래와 같이 viewController
와 view
단에서 이 메소드를 오버라이드하여 UI를 재구성하면 된다.
1 | override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { |
기타 바뀌는 것들
이외에도 Xcode 시스템적으로 자동으로 traitCollection의 변화에 따라 적용되는 것들이 있다.
- Interface Builder
인터페이스 빌더에서 +버튼을 누르면 traitCollection에 따른 변화를 줄 수가 있다.
- Asset Catalog
기기가 지원하는 해상도에 따라 이미지를 다르게 보여준다.
traitCollection을 잘 적용한다면 기기별 대응을 좀 더 잘 할 수 있을 것 같다. 지금까지는 오토레이아웃밖에 몰랐지만 말이다. 그리고 이번 공부를 하면서 느낀 점은 WWDC를 좀 더 챙겨봐야겠다고 생각이 들었다.