Stacks, Grids, and Outlines in SwiftUI
SwiftUI은 기본 레이아웃 요소들은 Compositional 하게 사용 되도록 설계되었다. 이들 각각을 사용, 조합하여 원하는 레이아웃을 구성할 수 있다.
Stacks
우린 VStack
과 HStack
의 조합으로 아래와 같은 갤러리 레이아웃을 구성할 수 있다. 그리고 이들 Stack만으로는 스크롤이 불가능하기 때문에 ScrollView
안에 이들을 구성하였다.
하지만 갤러리 이미지가 많아질수록 그 모든 이미지를 한 번에 불러오는 데 있어 문제가 발생한다. 이는 반응성을 저해하는 요소가 될 수 있다.
이를 위해 Lazy 하게 컨텐츠를 불러올 수 있는, 즉 처음 랜더링될 때 필요한 컨텐츠만 불러오고 이후 필요할 때 나머지를 컨텐츠를 불러올 수 있는 LazyVStack
과 LazyHStack
이 새로 생겼다.
이들을 통해 메모리 공간이 불필요하게 커지는 것을 방지할 수 있다. 사용법은 매우 간단하다.
위의 갤러리 레이아웃에서 별점을 위한 HStack
도 존재하는데, 이들 역시 Lazy 하게 구성해야 할까?
정답은 “아니오”다. 이들은 화면에 보여졌을 때 모든 컨텐츠를 한 번에 볼 수 있다. 그렇기 때문에 LazyHStack
을 사용해서 그 어떤 이득도 볼 수 없다. 만일 일반 Stack과 Lazy Stack 중 어떤 것을 사용해야 할지 고민된다면 일반 Stack을 사용하는 걸 권장한다.
Instruments를 사용해 프로파일링을 한 후 성능의 병목 현상을 발견했고 이를 해결할 때만 Lazy Stack을 사용하도록 하자
Grids
그리드 레이아웃을 위한 새로운 기본 레이아웃이 추가되었는데 LazyVGrid
와 LazyHGride
가 그것이다. 이들의 사용법 역시 그리 어렵진 않다.
LazyVGrid
기준으로 원하는 행의 구성 정보와 함께 기존의 VStack
코드를 대체하였다. 그리고 이런 행의 정보를 나타내는 GridItem
역시 새로 추가되었다.
GridItem
을 사용해 그리드 레이아웃의 각각의 아이템의 크기와 위치를 지정해 줄 수 있다.
이들은 기본적으로 유연하기(flexible) 때문에 위와 같이 세 개의 GridItem
을 사용하면 각 행의 너비는 모두 동일한 너비를 갖게 된다.
GridItem
은 단순히 갯수만이 아닌 최소 너비 값과 같은 특정 사이즈 크기를 이용해 원하는 그리드 레이아웃을 구성하는데 사용할 수 있다.
Lists
List
역시 기본 레이아웃 구성 요소 중 하나로 스크롤과 선택된 항목(selection) 관리와 같은 인터렉션을 지원하는 레이아웃 요소이다. List
는 항상 컨텐츠를 Lazy 하게 불러온다.
이뿐만 아니라 이번에 추가된 기능으로 우린 리스트를 통해 컨텐츠를 그룹화하여 표현할 수 있게 되었다.
children
keypath를 사용하는 생성자를 통해 우린 List
의 컨텐츠를 쉽게 그룹화할 수 있게 되었다. 내부적으로 어떻게 이것이 가능한지 살펴보도록 하자.
Outlines
OutlineGroup
은 ForEach
와 동일하게 데이터를 순회하지만 단일 계층의 flat 한 콜렉션 타입의 데이터를 순회하는 ForEach
와 달리 OutlineGroup
은 트리 구조 형태의 데이터 타입을 순회한다.
OutlineGroup
을 Section
과 함께 사용하면 .listStyle(_:)
에 따라 다양한 기본 스타일의 헤더 뷰를 사용할 수 있다.
이렇게 계층화된 데이터를 사용해 동일한 외형의 Row를 사용하는 것이 아니라 서로 다른 데이터 타입이지만 단순히 이들을 계층화하고, 보여주기와 숨기기 기능을 사용하고 싶다면 이번에 새로 추가된 DisclosureGroup
을 사용하면 된다.
OutlineGroup
이 내부적으로 어떻게 동작하는지 살펴보자.
- 예제의
OutlineGroup
은graphics
모델을 사용한다. OutlineGroup
은 동일한 모델을 사용하는ForEach
로 확장된다.ForEach
의body
는DisclosureGroup
으로graphics
의 아이템 하나를 사용한다.DisclosureGroup
은 다시 하나의graphic
를 데이터로 갖는OutlineGroup
을body
로 갖는다.
이런 1~4의 과정은 children
이 없는 graphic
을 찾을 때까지 반복된다. 이러한 계산 과정은 그룹이 확장되었을 때(사용자가 그룹을 확장시켰을 때)에만 진행되기 때문에 최소한의 과정만을 갖게 된다.