SwiftUI - ViewThatFits
안녕하세요. 그린입니다 🍏
이번 포스팅에서는 SwiftUI의 ViewThatFits 컴포넌트에 대해 알아보겠습니다 🙋🏻
오랜만에 정말 가볍게 요런것도 활용해볼 수 있구나 하는 주제이니 편하게 같이 훑어보시죠 😃
ViewThatFits
해당 컴포넌트는 SwiftUI에서 하위 자식 뷰들중에서 현재 사용 가능한 공간에 제일 적합한 뷰를 선택해 화면에 렌더링해주는 뷰 컴포넌트입니다.
즉, 해당 뷰 컴포넌트는 대게 다양한 화면 사이즈나 레이아웃에서 유연하게 뷰를 선택해서 표시할때 이용됩니다.
iOS 16.0 이상이라면 모두 적용할 수 있어요!
선언을 볼까요?
@MainActor @frozen @preconcurrency
struct ViewThatFits<Content> where Content : View
이렇게 일반적인 다른 뷰 컴포넌트와 다르지 않습니다.
제네릭으로 Content인 View 자체를 받아오죠.
이니셜라이저를 살펴볼까요?
nonisolated
init(
in axes: Axis.Set = [.horizontal, .vertical],
@ViewBuilder content: () -> Content
)
보시면 딱 두가지 조건밖에 없어요.
axes는 제안된 크기에 맞는 첫번째 하위 뷰를 선택하기 위해 하위 뷰를 제한할 방향 축이라고 보면 됩니다.
즉, 기본값으로 수평, 수직 모두 들어가있으니 해당 상황에 맞게 적절한 하위 뷰를 택하죠.
그런데, 해당 인자를 horizontal로 둔다면 수평 상황에 적절한 하위 뷰를 택하게 됩니다.
그 다음으로 뷰 빌더인 content가 있죠.
즉, 여러 하위 뷰들을 뷰빌더로 구현 제공하면 해당 ViewThatFits에서 순서상 첫번째부터 하위 뷰들이 적합한지 판단하고 그에 대해 그려주게 됩니다.
요점은 ViewThatFits은 초기화 시 제공된 하위 뷰들의 순서대로 현재 뷰에 나타내기 적합한지 판단합니다 🙋🏻
즉, 이상적으로 생각하는 크기에 맞는 첫번째 하위 뷰가 선택되는것이죠.
결국 우리는 구현 시 선호도 순서대로 뷰 코드를 순차적으로 작성해야 합니다.
이론 자체는 아주 간단하죠? 😃
그럼 실제로 한번 사용을 해볼까요?
ViewThatFits 사용하기
기본적인 사용
import SwiftUI
struct ContentView: View {
var body: some View {
ViewThatFits {
Text("이건 아주 아주 긴 문장을 나타내고 있습니다!!")
.font(.title)
.padding()
Text("짧은 문장")
.font(.title)
.padding()
Text("이건 비교적 짧은 문장입니다.")
.font(.title)
.padding()
}
}
}
코드를 보면, ViewThatFits을 사용하여 하위 뷰 컨텐츠로 순서대로 3개의 뷰를 넣었습니다.
여기서 어떤 뷰가 실제 화면에 그려질까요?
해당 Text가 한줄에 딱 다 표시되는게 이상적으로 생각하는거겠죠?
즉, 디바이스의 가로 사이즈보다 Text의 width가 크면 이상적이지 않다고 판단합니다.
그래서, 순차적으로 제일 위에 Text는 적합하지 않다고 생각하고 바로 다음 "짧은 문장" 텍스트가 뷰에 그려집니다.
근데 만약 세번째 Text가 두번째 Text보다 먼저 위치하면, 짧은 문장 텍스트가 더 넓이가 적더라도 세번째 Text도 충분히 현재 디바이스에서 가로 사이즈 적합하다고 판단하여 그려지게 됩니다.
이런식으로 보이는것처럼 말이죠!
이건 Portrait 즉, 일반적인 세로 모드 환경에서 나타나는것이죠?
앞서 우리는 초기화 시 axes 인자로 horizontal, vertical 모두 채택하고 있는걸 알 수 있었습니다.
즉, 가로/세로 모드에 따라 이상적인 사이즈가 달라져 채택하는 하위 뷰가 달라진다는것을 의미합니다.
그럼 현재 디바이스를 Landscape로 회전시켜 볼까요?
디바이스 가로모드에 맞게 첫번째 아주 아주 긴 문장 Text도 적합하다고 판단하여 바로 채택하여 나타내주고 있습니다 😃
이렇게, 기본적으로 ViewThatFits을 사용해 각 디바이스 모드 환경에 따라 적합한 뷰를 나타내줄때 아주 유용하겠죠?
다른 타입의 뷰를 이용하기
위 예시는 아주 동일한 템플릿의 Text를 가지고 이용해봤다면, 이렇게도 이용할 수 있습니다.
import SwiftUI
struct ContentView: View {
var body: some View {
ViewThatFits {
HStack(spacing: 10) {
Text("가로로 나타내보자")
.font(.title)
Text("가로로 길게 길게 길게 나타내보자!")
.font(.body)
}
VStack(spacing: 10) {
Text("세로로 나타내보자")
.font(.title)
Text("세로로 나타내보자!")
.font(.body)
}
}
}
}
두가지의 다른 타입 및 템플릿의 하위 뷰를 구성합니다.
즉, 위의 HStack 뷰는 가로 모드일때 최적화되었고 아래 VStack 뷰는 세로 모드일때 최적화 되었죠.
그럼 당연하게 가로, 세로에 따라 다른 뷰를 가지게 되죠.
좀 더 시각적으로 이해가 쉽게 아래 공식문서에서 제공된 코드를 가지고 뷰를 볼까요?
import SwiftUI
struct ContentView: View {
var uploadProgress: Double = 0.7
var body: some View {
ViewThatFits {
HStack {
Text("\(uploadProgress.formatted(.percent))")
ProgressView(value: uploadProgress)
.frame(width: 100)
}
ProgressView(value: uploadProgress)
.frame(width: 100)
Text("\(uploadProgress.formatted(.percent))")
}
}
}
뷰를 보시면, 하위로 3개의 뷰가 있습니다.
각기 다른 뷰를 나타내죠.
현재 코드라면 뷰를 확인할 때, 아래와 같이 진행률과 텍스트가 모두 나타나게 됩니다.
근데, 만약 첫번째 HStack의 frame width를 넓히면 어떻게 될까요?
진행률 프로그래스바만 나오고 텍스트는 안나오게 됩니다.
두번째 뷰도 width가 넓어지면 당연히 세번째 프로그래스바가 없이 텍스트만 나오는 뷰가 보여지겠죠ㅎㅎ
물론, 가로 모드로 하면 그에 따라 적절히 잘 보이겠죠!
마무리
이렇게 오늘 라이트한 주제로 ViewThatFits에 대해 알아봤습니다 🙋🏻
가볍게 오늘 영어 한단어 외우듯이 보기 편한 주제였어요ㅎㅎ
sizeclass도 유용하겠지만, 여러 기기 사이즈에 따라 적합히 대응할때 꼭 써볼만한 컴포넌트라 생각됩니다 😃